في بايثون، لماذا تكون القائمة [] عمومية تلقائيًا؟

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

سؤال

هذا سلوك غريب.

جرب هذا :

rep_i=0
print "rep_i is" , rep_i
def test():
  global rep_i #without Global this gives error but list , dict , and others dont
  if rep_i==0:
    print "Testing Integer %s" % rep_i
    rep_i=1
  return "Done"

rep_lst=[1,2,3]


def test2():
  if rep_lst[0]==1:
    print "Testing List %s" % rep_lst
  return "Done"


if __name__=="__main__":
  test()
  test2()

لماذا لا تحتاج القائمة إلى إعلان العالمية؟هل هي عالمية تلقائيًا؟

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

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

المحلول

إنها ليست عالمية تلقائيًا.

ومع ذلك، هناك فرق بين rep_i=1 و rep_lst[0]=1 - السابق يعيد الاسم rep_i, ، لذا global هناك حاجة لمنع إنشاء فتحة محلية بنفس الاسم.في الحالة الأخيرة، أنت تقوم فقط بتعديل كائن عام موجود، والذي يتم العثور عليه من خلال البحث العادي عن الاسم (يشبه تغيير إدخال القائمة استدعاء وظيفة عضو في القائمة، وهو ليس إعادة ربط الاسم).

لاختبار ذلك، حاول التعيين rep_lst=[] في test2 (أي.اضبطه على قائمة جديدة).إلا إذا أعلنت rep_lst global, ، لن تكون التأثيرات مرئية في الخارج test2 لأنه يتم إنشاء فتحة محلية بنفس الاسم وتظليل الفتحة العامة.

نصائح أخرى

ما عليك سوى استخدام global إذا كنت تقوم بتعيين الاسم العالمي.بدون global, ، تقوم المهمة بإنشاء محلي جديد.

لا يوجد شيء خاص حول كيفية القيام بذلك global ينطبق على القائمة —global يؤثر ببساطة على النطاق ودقة الاسم.

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

عندما يرى المترجم اسم متغير لأول مرة، فإنه يتطلع إلى نهاية كتلة التعليمات البرمجية الحالية، وإذا لم يكن لديك مهمة له في أي مكان داخل نفس كتلة التعليمات البرمجية، فإن المترجم يعتبره عالميًا.ومع ذلك، إذا قمت بذلك، فسيتم اعتبارها محلية، وأي إشارة إليها قبل التعيين ستؤدي إلى إنشاء ملف UnboundLocalError.هذا هو الخطأ الذي حصلت عليه.لهذا السبب عليك أن تعلن global rep_i.إذا لم تقم بتعيين rep_i, ، لن تحتاج إلى هذا الخط.

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

In [1]: # It won't work with small integers, as they are cached singletons in CPython

In [2]: a = 123123

In [3]: id (a)
Out[3]: 9116848

In [4]: a = 123123

In [5]: id(a)
Out[5]: 9116740

In [6]: # See, it changed

In [7]: # Now with lists

In [8]: l = [1,2,3]

In [9]: id(l)
Out[9]: 19885792

In [10]: l[1] = 2

In [11]: id(l)
Out[11]: 19885792

In [12]: # See, it is the same

In [13]: # But if i reassign the list, even to the same value

In [14]: l = [2,2,3]

In [15]: id(l)
Out[15]: 19884272

إذا قمت بتعيين قيمة جديدة ل rep_lst بداخل test2 (وليس فقط لأحد عناصره، كما فعلت) فلن يعمل بدون global علَم.في Python، إذا لم تقم بتعيين متغير داخل دالة، فسوف تبحث عن هذا المتغير في نطاقات أكثر عمومية حتى تجده.

على سبيل المثال، في مقطع التعليمات البرمجية هذا، قمت بتحديد القائمة عالميًا وداخليًا example().منذ المتغير في example() هو أقرب في نطاق example2() من العالمي، هذا هو ما سيتم استخدامه.

x = ["out"]

def example():
    x = ["in"]
    def example2():
        print x # will print ["in"]

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

فيما يلي مثال يوضح أن غير list/dict المتغير متاح في روتين فرعي، والمشكلة، كما يقول الجميع، هي فعل rebinding في نموذج التعليمات البرمجية الأصلي الخاص بك:

x = 1
def test():
    y = x + 1
    print y
test()

سترى هذه المطبوعات 2, ، بالرغم من x لم يتم الإعلان عنها عالميًا.

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