سؤال

فشل الاختبار التالي:

#!/usr/bin/env python
def f(*args):
    """
    >>> t = 1, -1
    >>> f(*map(lambda i: lambda: i, t))
    [1, -1]
    >>> f(*(lambda: i for i in t)) # -> [-1, -1]
    [1, -1]
    >>> f(*[lambda: i for i in t]) # -> [-1, -1]
    [1, -1]
    """
    alist = [a() for a in args]
    print(alist)

if __name__ == '__main__':
    import doctest; doctest.testmod()

بعبارة أخرى:

>>> t = 1, -1
>>> args = []
>>> for i in t:
...   args.append(lambda: i)
...
>>> map(lambda a: a(), args)
[-1, -1]
>>> args = []
>>> for i in t:
...   args.append((lambda i: lambda: i)(i))
...
>>> map(lambda a: a(), args)
[1, -1]
>>> args = []
>>> for i in t:
...   args.append(lambda i=i: i)
...
>>> map(lambda a: a(), args)
[1, -1]
هل كانت مفيدة؟

المحلول

أنها مختلفة، لأن قيمة i في كل من تعبير المولد وشركات القائمة يتم تقييمها بتكاسل، أي.عندما يتم استدعاء الوظائف المجهولة f.
بحلول ذلك الوقت، i يرتبط بالقيمة الأخيرة إذا t, ، وهو -1.

لذا، هذا هو ما يفعله فهم القائمة (كما هو الحال بالنسبة لـ genexp):

x = []
i = 1 # 1. from t
x.append(lambda: i)
i = -1 # 2. from t
x.append(lambda: i)

الآن تحمل لامدا إغلاقًا يشير إلى ذلك i, ، لكن i يرتبط بـ -1 في كلتا الحالتين، لأن هذه هي القيمة الأخيرة التي تم تعيينها لها.

إذا كنت تريد التأكد من أن لامدا تتلقى القيمة الحالية لـ i, ، يفعل

f(*[lambda u=i: u for i in t])

بهذه الطريقة، يمكنك فرض التقييم i في وقت إنشاء الإغلاق.

يحرر:هناك فرق واحد بين تعبيرات المولد وفهم القائمة:يقوم الأخير بتسريب متغير الحلقة إلى النطاق المحيط.

نصائح أخرى

يلتقط لامدا المتغيرات، وليس القيم، ومن ثم الكود

lambda : i

سيعود دائمًا القيمة i حالياً ملزمة في الإغلاق.بحلول الوقت الذي يتم استدعاؤه، تم تعيين هذه القيمة إلى -1.

للحصول على ما تريد، ستحتاج إلى التقاط الارتباط الفعلي في وقت إنشاء لامدا، عن طريق:

>>> f(*(lambda i=i: i for i in t)) # -> [-1, -1]
[1, -1]
>>> f(*[lambda i=i: i for i in t]) # -> [-1, -1]
[1, -1]

تعبير f = lambda: i يعادل:

def f():
    return i

تعبير g = lambda i=i: i يعادل:

def g(i=i):
    return i

i هو متغير حر في الحالة الأولى ويرتبط بمعلمة الدالة في الحالة الثانية، أي أنه متغير محلي في هذه الحالة.يتم تقييم قيم المعلمات الافتراضية في وقت تعريف الوظيفة.

تعبير المولد هو أقرب نطاق مرفق (حيث i تم تعريفه) ل i الاسم في lambda التعبير، لذلك i تم حلها في تلك الكتلة:

f(*(lambda: i for i in (1, -1)) # -> [-1, -1]

i هو متغير محلي لل lambda i: ... block، وبالتالي فإن الكائن الذي يشير إليه محدد في تلك الكتلة:

f(*map(lambda i: lambda: i, (1,-1))) # -> [1, -1]
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top