Каков механизм, позволяющий исправлениям Python Monkey в этом случае?
Может кто-нибудь объяснить логику, как это работает с интерпретатором Python? Является ли это поведение только локальным потоком? Почему назначение при импорте первого модуля сохраняется после импорта второго модуля? У меня просто была долгая сессия отладки, которая сводилась к этому.
external_library.py
def the_best():
print "The best!"
modify_external_library.py
import external_library
def the_best_2():
print "The best 2!"
external_library.the_best = the_best_2
main.py
import modify_external_library
import external_library
external_library.the_best()
Тестовое задание:
$ python main.py
The best 2!
4 ответа
Ничего нить местного об этом. somemodule.anattr = avalue
очень глобальное поведение! После этого назначения атрибут изменяется навсегда (до тех пор, пока, возможно, не будет изменен позже), несмотря ни на что.
Там нет таинственной механики в игре! Присвоение любому атрибуту объекта, который позволяет такое присваивание (как это делают объекты модуля), просто работает очевидным образом - ничего локального для потока, ничего странного - и присваивание атрибуту сохраняется, пока объект, атрибут которого вы ' Назначение сохраняется, конечно.
Повторный import external_library
не перезагружает модуль (reload
это совершенно отдельный встроенный и import
не называет это!) - это просто проверяет sys.modules
находит external_library
ключ в этом dict
и связывает соответствующее значение (которое ранее было изменено этим назначением) с именем external_library
в соответствующем пространстве имен (здесь, глобалы модуля main
).
Модули являются экземплярами классов нового стиля. Когда вы изменяете атрибуты модуля (в данном случае функцию), вы модифицируете экземпляр модуля. При попытке импортировать его снова (с import external_library
), вы просто получаете тот же объект модуля, на который уже ссылается modify_external_library.py
,
Изменить: Конечно, попытка импортировать тот же модуль снова не работает (как указывает Алекс Мартелли). После загрузки модули не инициализируются повторно, если это не сделано явно с reload
,
Как указал Алекс, нужно перезагрузить external_library
простой импорт ничего не даст, если он уже был импортирован. Вы можете проверить это, поставив print
заявления в ваш external_library
а также modify_external_library
модули.
import modify_external_library
#import external_library
reload(external_library)
external_library.the_best()
выход
The best!
Патч обезьяны работает, потому что классы модифицируются в python, но механизм, который позволяет ему распространяться следующим образом, заключается в том, что после импорта и инициализации любого модуля последующий импорт просто добавляет существующий экземпляр в локальное пространство имен без повторного запуска инициализации, это также сохраняет время, когда модуль имеет много инициализации, а также позволяет патчи обезьяны.