سؤال

كيف بالضبط Python تقييم سمات الطبقة؟ لقد تعثرت عبر quirk المثيرة للاهتمام (في بيثون 2.5.2) الذي أود شرحه.

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

هذا هو المثال القريب. لاحظ أن الفرق الوحيد هو ذلك Brie يستخدم تعبير المولد ، بينما Cheddar يستخدم فهم قائمة.

# Using a generator expression as the argument to list() fails
>>> class Brie :
...     base = 2
...     powers = list(base**i for i in xrange(5))
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in Brie
  File "<stdin>", line 3, in <genexpr>
NameError: global name 'base' is not defined

# Using a list comprehension works
>>> class Cheddar :
...     base = 2
...     powers = [base**i for i in xrange(5)]
... 
>>> Cheddar.powers
[1, 2, 4, 8, 16]

# Using a list comprehension as the argument to list() works
>>> class Edam :
...     base = 2
...     powers = list([base**i for i in xrange(5)])
...
>>> Edam.powers
[1, 2, 4, 8, 16]

(كانت حالتي الفعلية أكثر تعقيدًا ، وكنت أقوم بإنشاءيل ، لكن هذا هو الحد الأدنى الذي يمكن أن أجده.)

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

هل هناك سبب لذلك ، وإذا كان الأمر كذلك ، كيف يجب أن أفكر في ميكانيكا التقييم لسمات الفصل؟

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

المحلول

نعم ، إنها مراوغة بعض الشيء ، هذا. لا يقدم الفصل حقًا نطاقًا جديدًا ، إنه مجرد نوع من يبدو قليلاً كما يفعل ؛ بنيات مثل هذا يعرض الفرق.

الفكرة هي أنه عندما تستخدم تعبير المولد ، فإنه يعادل القيام بذلك باستخدام Lambda:

class Brie(object):
    base= 2
    powers= map(lambda i: base**i, xrange(5))

أو صراحة كبيان وظيفة:

class Brie(object):
    base= 2

    def __generatePowers():
        for i in xrange(5):
            yield base**i

    powers= list(__generatePowers())

في هذه الحالة ، من الواضح ذلك base ليس في نطاق __generatePowers; ؛ استثناء نتائج لكليهما (ما لم تكن محظوظًا بما يكفي لتوضيح ملف base عالمي ، وفي هذه الحالة تحصل على خطأ).

لا يحدث هذا بالنسبة إلى اختصارات القائمة بسبب بعض التفاصيل الداخلية حول كيفية تقييمها ، ولكن هذا السلوك يختفي في Python 3 والذي سيفشل على قدم المساواة في كلتا الحالتين. بعض النقاش هنا.

يمكن أن يكون هناك حل بديل باستخدام Lambda مع نفس التقنية التي اعتمدنا عليها في الأيام الخوالي السيئة قبل nested_scopes:

class Brie(object):
    base= 2
    powers= map(lambda i, base= base: base**i, xrange(5))

نصائح أخرى

من عند بيب 289:

بعد استكشاف العديد من الاحتمالات ، ظهر إجماع على أنه كان من الصعب فهم مشكلات الربط وأنه ينبغي تشجيع المستخدمين بشدة على استخدام تعبيرات المولدات داخل الوظائف التي تستهلك حججهم على الفور. بالنسبة للتطبيقات الأكثر تعقيدًا ، تكون تعريفات المولدات الكاملة متفوقة دائمًا من حيث أن تكون واضحة حول النطاق والعمر والربط [6].

6] (1 ، 2) مناقشة التصحيح والبقع البديلة على صياغة المصدر http://www.python.org/sf/872326

هذه هي الطريقة التي يتم بها تحديد تعبيرات المولدات بقدر ما أستطيع.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top