Какова область применения импортированных классов в Python?
Вопрос
Извините, пожалуйста, за расплывчатое название.Если у кого-то есть предложения, пожалуйста, дайте мне знать!Также, пожалуйста, используйте более подходящие теги!
Проблема
Я хочу, чтобы экземпляр импортированного класса мог просматривать объекты в области видимости (глобальные, локальные) импортера.Поскольку я не уверен в точном механизме, который здесь работает, я могу гораздо лучше описать его фрагментами, чем словами.
## File 1
def f1(): print "go f1!"
class C1(object):
def do_eval(self,x): # maybe this should be do_evil, given what happens
print "evaling"
eval(x)
eval(x,globals(),locals())
Затем запустите этот код из итеративной сессии, там будет много NameErrors
## interactive
class C2(object):
def do_eval(self,x): # maybe this should be do_evil, given what happens
print "evaling"
eval(x)
eval(x,globals(),locals())
def f2():
print "go f2!"
from file1 import C1
import file1
C1().do_eval('file1.f1()')
C1().do_eval('f1()')
C1().do_eval('f2()')
file1.C1().do_eval('file1.f1()')
file1.C1().do_eval('f1()')
file1.C1().do_eval('f2()')
C2().do_eval('f2()')
C2().do_eval('file1.f1()')
C2().do_eval('f1()')
Есть ли общая идиома/шаблон для такого рода задач?Неужели я лаю не на то дерево?
Решение
В этом примере вы можете просто передать функции как объекты методам в C1
:
>>> class C1(object):
>>> def eval(self, x):
>>> x()
>>>
>>> def f2(): print "go f2"
>>> c = C1()
>>> c.eval(f2)
go f2
В Python вы можете передавать функции и классы другим методам и вызывать/создавать их там.
Если вы хотите действительно оценить строку кода, вам необходимо указать среду, как уже упоминал Томас.
Ваш модуль сверху, немного изменился:
## File 1
def f1(): print "go f1!"
class C1(object):
def do_eval(self, x, e_globals = globals(), e_locals = locals()):
eval(x, e_globals, e_locals)
Теперь в интерактивном интерпретаторе:
>>> def f2():
>>> print "go f2!"
>>> from file1 import * # 1
>>> C1().do_eval("f2()") # 2
NameError: name 'f2' is not defined
>>> C1().do_eval("f2()", globals(), locals()) #3
go f2!
>>> C1().do_eval("f1()", globals(), locals()) #4
go f1!
Некоторые аннотации
- Сюда мы вставляем все объекты из
file1
в пространство имен этого модуля f2
не находится в пространстве именfile1
, поэтому мы получаемNameError
- Теперь мы явно передаем среду, и код можно оценить.
f1
находится в пространстве имен этого модуля, поскольку мы его импортировали
Редактировать:Добавлен пример кода о том, как явно передать среду для eval
.
Другие советы
Функции всегда выполняются в той области, в которой они определены, как и методы и тела классов.Они никогда не выполняются в другой области.Поскольку импорт — это всего лишь еще один оператор присваивания, а все в Python — это ссылки, функции, классы и модули даже не знают, куда они импортируются.
Вы можете сделать две вещи:явно передайте «среду», которую вы хотите, чтобы они использовали, или используйте хакерство стека для доступа к пространству имен вызывающего абонента.Первое предпочтительнее второго, поскольку оно не так зависит от реализации и не столь хрупко, как второе.
Возможно, вы захотите взглянуть на класс string.Template, который пытается сделать нечто подобное.