بايثون:هل تريد إعادة تحميل المكون Y المستورد باستخدام "من X import Y"؟

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

  •  20-09-2019
  •  | 
  •  

سؤال

في Python، بمجرد استيراد الوحدة X في جلسة مترجم باستخدام import X, ، وتتغير الوحدة من الخارج، يمكنني إعادة تحميل الوحدة بها reload(X).تصبح التغييرات متاحة بعد ذلك في جلسة المترجم الفوري.

أتساءل عما إذا كان هذا ممكنًا أيضًا عندما أقوم باستيراد مكون Y من الوحدة X باستخدام from X import Y.

البيان reload Y لا يعمل، نظرًا لأن Y ليس وحدة نمطية بحد ذاتها، ولكنه مجرد مكون (في هذه الحالة فئة) داخل الوحدة النمطية.

هل من الممكن على الإطلاق إعادة تحميل المكونات الفردية للوحدة النمطية دون مغادرة جلسة المترجم الفوري (أو استيراد الوحدة بأكملها)؟

يحرر:

للتوضيح السؤال يتعلق باستيراد أ الفئة أو الوظيفة Y من الوحدة X وإعادة التحميل عند التغيير، وليس الوحدة Y من الحزمة X.

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

المحلول

إذا كانت Y وحدة نمطية (و X حزمة) reload(Y) سيكون جيدًا - وإلا، فسترى لماذا تقول أدلة أسلوب بايثون الجيدة (مثل صاحب العمل). أبداً استيراد أي شيء يستثني وحدة نمطية (وهذا أحد الأسباب الرائعة العديدة - ومع ذلك لا يزال الأشخاص يستمرون في استيراد الوظائف والفئات مباشرةً، بغض النظر عن مدى شرحي لذلك) لا فكرة جيدة؛-).

نصائح أخرى

إجابة

من اختباراتي.الجواب ملحوظ، مما يوحي بسيطة reload(X), ، لا يعمل.

مما أستطيع أن أقول الإجابة الصحيحة هو:

# python3.x would require
# from importlib import reload
import X
reload( X )
from X import Y

امتحان

كان اختباري هو التالي (Python 2.6.5 + bpython 0.9.5.2)

X.py:

def Y():
    print "Test 1"

بيثون:

>>> from X import Y
>>> print Y()
Test 1
>>> # Edit X.py to say "Test 2"
>>> print Y()
Test 1
>>> reload( X )  # doesn't work because X not imported yet
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'X' is not defined
>>> import X
>>> print Y()
Test 1
>>> print X.Y()
Test 1
>>> reload( X ) # No effect on previous "from" statements
>>> print Y()
Test 1
>>> print X.Y() # first one that indicates refresh
Test 2
>>> from X import Y
>>> print Y()
Test 2 
>>> # Finally get what we were after

أولاً، يجب ألا تستخدم إعادة التحميل على الإطلاق، إذا كان بإمكانك تجنب ذلك.لكن لنفترض أن لديك أسبابك (أي:التصحيح داخل IDLE).

لن تؤدي إعادة تحميل المكتبة إلى إعادة الأسماء إلى مساحة اسم الوحدة.للقيام بذلك، فقط قم بإعادة تعيين المتغيرات:

f = open('zoo.py', 'w')
f.write("snakes = ['viper','anaconda']\n")
f.close()

from zoo import snakes
print snakes

f = open('zoo.py', 'w')
f.write("snakes = ['black-adder','boa constrictor']\n")
f.close()

import zoo
reload(zoo)
snakes = zoo.snakes # the variable 'snakes' is now reloaded

print snakes

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

from modulename import func

import sys
reload(sys.modules['modulename'])
from modulename import func

إذا كنت تريد أن تفعل هذا:

from mymodule import myobject

افعل هذا بدلاً من ذلك:

import mymodule
myobject=mymodule.myobject

يمكنك الآن استخدام myobject بنفس الطريقة التي كنت تخطط لها (بدون مراجع mymodule المملة وغير القابلة للقراءة في كل مكان).

إذا كنت تعمل بشكل تفاعلي وتريد إعادة تحميل myobject من mymodule، فيمكنك الآن استخدام:

reload(mymodule)
myobject=mymodule.myobject

على افتراض أنك استخدمت from X import Y, ، لديك خياران:

reload(sys.modules['X'])
reload(sys.modules[__name__]) # or explicitly name your module

أو

Y=reload(sys.modules['X']).Y

بعض الاعتبارات:

أ.إذا لم يكن نطاق الاستيراد على مستوى الوحدة النمطية (على سبيل المثال، ز:استيراد في دالة) - يجب عليك استخدام الإصدار الثاني.

ب.إذا تم استيراد Y إلى X من وحدة أخرى (Z) - فيجب عليك إعادة تحميل Z، ثم إعادة تحميل X ثم إعادة تحميل الوحدة الخاصة بك، وحتى إعادة تحميل جميع الوحدات النمطية الخاصة بك (على سبيل المثال، ز:استخدام [ reload(mod) for mod in sys.modules.values() if type(mod) == type(sys) ]) قد يعيد تحميل X قبل إعادة تحميل Z - ومن ثم عدم تحديث قيمة Y.

  1. reload() وحدة X,
  2. reload() استيراد الوحدة النمطية Y من X.

لاحظ أن إعادة التحميل لن تغير الكائنات التي تم إنشاؤها بالفعل والمرتبطة بمساحات أسماء أخرى (حتى إذا كنت تتبع دليل النمط من Alex).

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

لنفترض أن لدي شجرة المصدر التالية:

- foo
  - __init__.py
  - bar.py

بالمحتوى التالي:

الحرف الأول.py:

from bar import Bar, Quux

bar.py:

print "Loading bar"

class Bar(object):
  @property
  def x(self):
     return 42

class Quux(Bar):
  object_count = 0
  def __init__(self):
     self.count = self.object_count
     self.__class__.object_count += 1
  @property
  def x(self):
     return super(Quux,self).x + 1
  def __repr__(self):
     return 'Quux[%d, x=%d]' % (self.count, self.x)

وهذا يعمل بشكل جيد دون استخدام reload:

>>> from foo import Quux
Loading bar
>>> Quux()
Quux[0, x=43]
>>> Quux()
Quux[1, x=43]
>>> Quux()
Quux[2, x=43]

لكن حاول إعادة التحميل ولن يكون له أي تأثير أو سيفسد الأشياء:

>>> import foo
Loading bar
>>> from foo import Quux
>>> Quux()
Quux[0, x=43]
>>> Quux()
Quux[1, x=43]
>>> reload(foo)
<module 'foo' from 'foo\__init__.pyc'>
>>> Quux()
Quux[2, x=43]
>>> from foo import Quux
>>> Quux()
Quux[3, x=43]
>>> reload(foo.bar)
Loading bar
<module 'foo.bar' from 'foo\bar.pyc'>
>>> Quux()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "foo\bar.py", line 17, in __repr__
    return 'Quux[%d, x=%d]' % (self.count, self.x)
  File "foo\bar.py", line 15, in x
    return super(Quux,self).x + 1
TypeError: super(type, obj): obj must be an instance or subtype of type
>>> Quux().count
5
>>> Quux().count
6
>>> Quux = foo.bar.Quux
>>> Quux()
Quux[0, x=43]
>>> foo.Quux()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "foo\bar.py", line 17, in __repr__
    return 'Quux[%d, x=%d]' % (self.count, self.x)
  File "foo\bar.py", line 15, in x
    return super(Quux,self).x + 1
TypeError: super(type, obj): obj must be an instance or subtype of type
>>> foo.Quux().count
8

الطريقة الوحيدة التي يمكنني من خلالها ضمان bar تم إعادة تحميل الوحدة الفرعية إلى reload(foo.bar);الطريقة الوحيدة التي يمكنني من خلالها الوصول إلى إعادة التحميل Quux الفصل هو الوصول إليه والاستيلاء عليه من الوحدة الفرعية المعاد تحميلها؛لكن ال foo الوحدة نفسها ظلت متمسكة بالأصل Quux كائن فئة، ويفترض أنه يستخدم from bar import Bar, Quux (بدلا من import bar تليها Quux = bar.Quux);علاوة على ذلك Quux لقد خرج الفصل عن المزامنة مع نفسه، وهو أمر غريب تمامًا.

إذا كنت تعمل في بيئة jupyter، ولديك بالفعل from module import function يمكن استخدام الوظيفة السحرية، autoreload بواسطة

%load_ext autoreload
%autoreload
from module import function

مقدمة autoreload في IPython معطى هنا.

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