الكلمة الأساسية "النهائية" المكافئة للمتغيرات في بايثون؟

StackOverflow https://stackoverflow.com/questions/802578

  •  03-07-2019
  •  | 
  •  

سؤال

لم أتمكن من العثور على وثائق مكافئة لجافا final في بايثون، هل هناك شيء من هذا القبيل؟

أقوم بإنشاء لقطة لكائن (تُستخدم للاستعادة في حالة فشل أي شيء)؛بمجرد تعيين متغير النسخ الاحتياطي هذا، لا ينبغي تعديله - ستكون الميزة النهائية في بايثون جيدة لهذا الغرض.

هل كانت مفيدة؟

المحلول

وجود متغير في جافا final يعني بشكل أساسي أنه بمجرد تعيين متغير ، لا يجوز لك إعادة تعيين هذا المتغير للإشارة إلى كائن آخر. هذا في الواقع لا يعني أنه لا يمكن تعديل الكائن. على سبيل المثال ، يعمل رمز Java التالي بشكل جيد:

public final List<String> messages = new LinkedList<String>();

public void addMessage()
{
    messages.add("Hello World!");  // this mutates the messages list
}

لكن ما يلي لن يتجمع:

public final List<String> messages = new LinkedList<String>();

public void changeMessages()
{
    messages = new ArrayList<String>();  // can't change a final variable
}

لذا فإن سؤالك يدور حول ما إذا كان final موجود في بيثون. لم يحدث ذلك.

ومع ذلك ، فإن Python لديه هياكل بيانات غير قابلة للتغيير. على سبيل المثال ، بينما يمكنك تحوير أ list, ، لا يمكنك تحوير أ tuple. يمكنك تحوير أ set ولكن ليس أ frozenset, ، إلخ.

تتمثل نصيحتي في عدم القلق بشأن فرض عدم التصنيف على مستوى اللغة والركوب ببساطة على التأكد من أنك لا تكتب أي رمز يتحول هذه الكائنات بعد تعيينها.

نصائح أخرى

لا يوجد "نهائي" مكافئ في بيثون.

ولكن ، لإنشاء حقول للقراءة فقط من مثيلات الفصل ، يمكنك استخدام منشأه وظيفة.

يحرر: ربما تريد شيئًا كهذا:

class WriteOnceReadWhenever:
    def __setattr__(self, attr, value):
        if hasattr(self, attr):
            raise Exception("Attempting to alter read-only value")

        self.__dict__[attr] = value

يعد متغير التعيين مرة واحدة مشكلة في التصميم.يمكنك تصميم التطبيق الخاص بك بطريقة يتم فيها تعيين المتغير مرة واحدة فقط.

ومع ذلك، إذا كنت تريد التحقق من تصميمك أثناء التشغيل، فيمكنك إجراء ذلك باستخدام غلاف حول الكائن.

class OnePingOnlyPleaseVassily( object ):
    def __init__( self ):
        self.value= None
    def set( self, value ):
        if self.value is not None:
            raise Exception( "Already set.")
        self.value= value

someStateMemo= OnePingOnlyPleaseVassily()
someStateMemo.set( aValue ) # works
someStateMemo.set( aValue ) # fails

هذا أمر صعب، لكنه سيكتشف مشاكل التصميم في وقت التشغيل.

لا يوجد شيء من هذا القبيل. بشكل عام ، فإن موقف Python هو "إذا كنت لا تريد هذا التعديل ، فلا تعدله". من غير المرجح أن يتجول عملاء واجهة برمجة التطبيقات في واجهة برمجة تطبيقات حول الداخلية غير الموثقة على أي حال.

يمكنك ، على ما أظن ، العمل حول هذا باستخدام tuples أو namedtuples للأجزاء ذات الصلة من النموذج الخاص بك ، والتي تكون غير قابلة للتغيير بطبيعتها. لا يزال هذا لا يساعد في أي جزء من النموذج الخاص بك يجب أن يكون قابلاً للتغيير بالطبع.

بيثون ليس لديه ما يعادل "النهائي". ليس لديها "عام" و "محمي" أيضًا ، باستثناء تسمية الاتفاقية. ليس هذا "العبودية والانضباط".

يمكنك محاكاة شيء كهذا من خلال بروتوكول واصف, ، لأنه يسمح بتحديد القراءة ووضع متغير بالطريقة التي ترغب فيها.

class Foo(object):

  @property
  def myvar(self):
     # return value here

  @myvar.setter
  def myvar(self, newvalue):
     # do nothing if some condition is met

a = Foo()
print a.myvar
a.myvar = 5 # does nothing if you don't want to

http://code.activestate.com/recipes/576527/ يحدد وظيفة التجميد ، على الرغم من أنها لا تعمل بشكل مثالي.

سأفكر فقط تركها قابلة للتغيير.

على الرغم من أن هذا سؤال قديم ، فقد اعتقدت أنني سأضيف خيارًا محتملًا آخر: يمكنك أيضًا استخدامه assert للتحقق من متغير يتم تعيينه على ما قصدته في الأصل أن يتم ضبطه على - فحص مزدوج إذا كنت تريد. على الرغم من أن هذا ليس هو نفسه final في Java ، يمكن استخدامه لإنشاء تأثير مماثل:

PI = 3.14
radius = 3

try:
    assert PI == 3.14
    print PI * radius**2
except AssertionError:
    print "Yikes."

كما رأينا أعلاه ، إذا PI لم يتم تعيين لسبب ما 3.14, ، و AssertionError سيتم إلقاؤه ، لذا أ try/except ربما تكون كتلة إضافة حكيمة. بغض النظر ، قد يكون مفيدًا اعتمادًا على وضعك.

Python في الواقع ليس لديه نوع نهائي ، فهو يحتوي على أنواع غير قابلة للتغيير مثل tuples ولكن هذا شيء آخر.

بعض الإجابات الأخرى هنا تجعل الفصول المليئة بالمتغيرات النهائية الزائفة وأفضل أن يكون لدى صفي فقط بعض الأنواع النهائية ، لذلك أقترح استخدام واصف لإنشاء النوع النهائي:

from typing import TypeVar, Generic, Type

T = TypeVar('T')

class FinalProperty(Generic[T]):
    def __init__(self, value: T):
        self.__value = value
    def __get__(self, instance: Type, owner) -> T:
        return self.__value
    def __set__(self, instance: Type, value: T) -> None:
        raise ValueError("Final types can't be set")

إذا كنت تستخدم هذا الفصل مثل ذلك:

class SomeJob:
    FAILED = FinalProperty[str]("Failed")

بعد ذلك ، لن تتمكن من تعيين هذا المتغير في أي مثيل من تلك الفئة. لسوء الحظ ، كما هو الحال مع AntriteOnceread ، لا يزال بإمكانك تعيين متغير الفصل.

job = SomeJob()
job.FAILED = "Error, this will trigger the ValueError"
SomeJob.FAILED = "However this still works and breaks the protection afterwards"
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top