بيثون جلوبل, المحليين, و UnboundLocalError
-
03-07-2019 - |
سؤال
ركضت عبر هذه الحالة من UnboundLocalError
في الآونة الأخيرة, والتي يبدو غريبا:
import pprint
def main():
if 'pprint' in globals(): print 'pprint is in globals()'
pprint.pprint('Spam')
from pprint import pprint
pprint('Eggs')
if __name__ == '__main__': main()
والتي تنتج:
pprint is in globals()
Traceback (most recent call last):
File "weird.py", line 9, in <module>
if __name__ == '__main__': main()
File "weird.py", line 5, in main
pprint.pprint('Spam')
UnboundLocalError: local variable 'pprint' referenced before assignment
pprint
هو بوضوح لا بد في globals
, و ستكون ملزمة في locals
في البيان التالي.شخص ما يمكن أن نقدم تفسيرا لماذا ليس سعيدا حل pprint
ربط في globals
إلى هنا ؟
تحرير: شكرا على الردود الجيدة يمكنني توضيح سؤالي ذات الصلة المصطلحات:
في وقت الترجمة المعرف pprint
تم وضع علامة المحلي إلى الإطار.لا تنفيذ نموذج لها أي تمييز حيث ضمن الإطار المحلي معرف غير ملزمة ؟ يمكن أن تقول "تشير إلى عالمية ملزمة حتى هذه بايت كود التعليمات ، وفي هذه المرحلة تم انتعاش المحلية ملزمة" أو تنفيذ نموذج لا حساب هذا ؟
المحلول
يبدو أن الثعبان يرى from pprint import pprint
خط وعلامات pprint
كاسم المحلية إلى main()
قبل تنفيذ أي رمز.منذ الثعبان يعتقد pprint يجب أن يكون متغير محلي ، الرجوع مع pprint.pprint()
قبل "تعيين" مع from..import
بيان ذلك يلقي هذا الخطأ.
هذا الشعور بقدر ما أنا يمكن أن تجعل من ذلك.
الأخلاقية, بالطبع, هو دائما وضع تلك import
البيانات في الجزء العلوي من نطاق.
نصائح أخرى
أين المفاجأة ؟ أي متغير العالمية على نطاق أنك تعيين داخل هذا النطاق يتم وضع علامة المحلية إلى نطاق من قبل المترجم.
إذا الواردات سيكون التعامل معها بشكل مختلف ، أن سيكون من المستغرب imho.
قد جعل قضية عدم تسمية وحدات بعد الرموز المستخدمة فيه ، أو العكس ، على الرغم من.
حسنا, هذا كان مثيرا للاهتمام بما فيه الكفاية بالنسبة لي أن تجربة قليلا و قرأت من خلال http://docs.python.org/reference/executionmodel.html
ثم فعل بعض ترقيع مع التعليمات البرمجية الخاصة بك هنا وهناك ، وهذا هو ما يمكن أن تجد:
كود:
import pprint
def two():
from pprint import pprint
print globals()['pprint']
pprint('Eggs')
print globals()['pprint']
def main():
if 'pprint' in globals():
print 'pprint is in globals()'
global pprint
print globals()['pprint']
pprint.pprint('Spam')
from pprint import pprint
print globals()['pprint']
pprint('Eggs')
def three():
print globals()['pprint']
pprint.pprint('Spam')
if __name__ == '__main__':
two()
print('\n')
three()
print('\n')
main()
الإخراج:
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Eggs'
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Spam'
pprint is in globals()
<module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>
'Spam'
<function pprint at 0xb7d596f4>
'Eggs'
في طريقة two()
from pprint import pprint
ولكن لا يلغي اسم pprint
في globals
, منذ global
الكلمة الرئيسية لا تستخدم في نطاق two()
.
في طريقة three()
إذ لا يوجد أي إعلان pprint
اسم النطاق المحلي الافتراضي إلى اسم عالمي pprint
الذي هو وحدة
في حين أنه في main()
, في أول الكلمة global
يستخدم لذلك جميع الإشارات إلى pprint
في نطاق الأسلوب main()
سوف أشير إلى global
اسم pprint
.والتي كما نرى هو وحدة في البداية و هو تنقضها في global
namespace
مع الأسلوب كما نفعل from pprint import pprint
على الرغم من أن هذا قد لا تكون الإجابة على السؤال على هذا النحو ، ولكن مع ذلك لها بعض الحقائق المثيرة للاهتمام أعتقد.
=====================
تحرير آخر الشيء المثير للاهتمام.
إذا كان لديك وحدة تقول:
mod1
from datetime import datetime
def foo():
print "bar"
و طريقة أخرى يقول:
mod2
import datetime
from mod1 import *
if __name__ == '__main__':
print datetime.datetime.now()
والتي للوهلة الأولى يبدو صحيحا لأن لديك المستوردة وحدة datetime
في mod2
.
الآن إذا حاولت تشغيل mod2 كبرنامج نصي وسوف رمي خطأ:
Traceback (most recent call last):
File "mod2.py", line 5, in <module>
print datetime.datetime.now()
AttributeError: type object 'datetime.datetime' has no attribute 'datetime'
لأن استيراد الثاني from mod2 import *
وقد تنقضها اسم datetime
في مساحة الاسم ، وبالتالي أول import datetime
لم يعد صالحا.
الأخلاقية:وبالتالي ترتيب الواردات طبيعة الواردات (من x استيراد *) والوعي الواردات في استيراد وحدات - المسائل.
هذا السؤال تم الإجابة عليها قبل عدة أسابيع, ولكن أعتقد أنني يمكن توضيح الإجابات قليلا.أولا بعض الحقائق.
1:في بيثون ،
import foo
هو بالضبط تقريبا نفس
foo = __import__("foo", globals(), locals(), [], -1)
2:عند تنفيذ التعليمات البرمجية في وظيفة ، إذا كان الثعبان لقاءات متغير لم يتم تعريفها في وظيفة حتى الآن ، يبدو في النطاق العالمي.
3:الثعبان لديه الأمثل ويستخدم على وظائف يسمى "السكان المحليين".عندما الثعبان tokenizes وظيفة ، ومن يتتبع جميع المتغيرات التي قمت بتعيينها.فإنه يعين كل من هذه المتغيرات عدد من مفردة النغمة زيادة عدد صحيح.عندما بيثون يعمل وظيفة ، فإنه يخلق مجموعة مع العديد من فتحات كما أن هناك المتغيرات المحلية ، يعين كل فتحة القيمة الخاصة التي تعني "لم يتم تعيينه حتى الآن" ، حيث قيم هذه المتغيرات المخزنة.إذا كنت المرجعية المحلية التي لم يتم تعيينه حتى الآن ، بيثون يرى أن قيمة خاصة و يلقي UnboundLocalValue استثناء.
المسرح هو الآن.الخاص بك "من pprint استيراد pprint" هو في الحقيقة شكل من أشكال التنازل.لذلك الثعبان يخلق متغير محلي يسمى "pprint" التي تسبب انسداد العالمي المتغير.ثم عند الرجوع إلى "pprint.pprint" في الوظيفة ، يمكنك ضرب قيمة خاصة و الثعبان يطرح الاستثناء.إذا لم يكن لديك أن استيراد البيان في وظيفة ، بيثون استخدام نظرة طبيعية في السكان المحليين-أولا-ثم أنظر في جلوبل القرار وإيجاد pprint وحدة في جلوبل.
إلى إزالة الغموض هذا يمكنك استخدام "العالمية" الكلمة.الآن كنت قد عملت بالفعل الماضي مشكلتك وأنا لا أعرف ما إذا كنت حقا بحاجة إلى "العالمية" أو إذا كان بعض نهج آخر دعا.