الكلمة الأساسية "النهائية" المكافئة للمتغيرات في بايثون؟
سؤال
لم أتمكن من العثور على وثائق مكافئة لجافا 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"