2013-02-12 5 views
3

У меня есть сценарий следующим образомКак разрешить глобальную переменную в модуле?

from mapper import Mapper 

class A(object): 
    def foo(self): 
     print "world" 

a = A() 
a.foo() 
Mapper['test']() 

с Mapper определены в файле mapper.py:

Mapper = {'test': a.foo} 

, где я хочу, чтобы определить вызов функции ссылки объект не определен в mapper.py, но в оригинале код. Однако выше код выдает ошибку

NameError: name 'a' is not defined 

, который делает вид смысла, так как a не определен mapper.py сам. Тем не менее, можно ли изменить код, чтобы код имел разрешение имен в самом главном коде или с использованием globals или что-то в этом роде?

Чтобы решить эту проблему, я мог бы указать реализацию в mapper.py как текст и использовать eval в основном коде, но я бы хотел избежать использования eval.

Дополнительная информация:

  • Полное определение функции должно быть сделано в mapper.py
  • Это не известно заранее, что экземпляр a есть, или от того, что Клас его экземпляра.

ответ

1

Запрет на дыры безопасности, как eval, нельзя использовать имя a в mapper.py, если только имя не определено где-то в mapper.py или импортированы из другого модуля. Невозможно просто позволить mapper.py автоматически и бесшумно получить доступ к значению a из другого модуля.

Кроме того, если вы используете его только в дикторе, как в вашем примере, то a.foo будет оцениваться сразу же после создания dict. Это не будет ждать, пока вы на самом деле вызовите функцию; как только он оценивает a.foo, чтобы создать dict, он потерпит неудачу, потому что он не знает, что такое a.

Вы можете обойти эту проблему, второй обернув элемент в функции (с помощью лямбда для краткости):

Mapper = {'test': lambda: a.foo} 

. , , но это все равно не поможет, если вы не сможете каким-то образом получить a, который будет доступен внутри mapper.py.

Одним из возможных вариантов является параметризация ваш Mapper от «загадочного» объекта, а затем передать этот объект из-за пределов:

# mapper.py 
Mapper = {'test': lambda a: a.foo} 

# other module 
from mapper import Mapper 
Mapper['test'](a)() 

Или, подобное тому, что mgilson предложил, вы можете «зарегистрировать» объект a с Mapper как-то. Это позволяет передать объект a только один раз, чтобы зарегистрировать его, и тогда вы не должны передать его для каждого вызова:

# mapper.py 
Mapper = {'test': lambda a: Mapper['a'].foo} 

# other module 
from mapper import Mapper 
Mapper['a'] = a 
Mapper['test']()() 

Примечание два набора круглых скобках в конце концов там: один набор для оценки lambda и извлеките функцию, которую вы хотите вызвать, и второй набор, чтобы фактически вызвать эту функцию. Вы могли бы сделать подобное предложение, вместо того, чтобы использовать Mapper['a'] в качестве эталона, используя переменную уровня модуля:

# mapper.py 
Mapper = {'test': lambda: a.foo} 

# other module 
import mapper 
Mapper = mapper.Mapper 

mapper.a = a 
Mapper['test']()() 

Обратите внимание, что это требует от вас сделать import mapper для того, чтобы установить переменную модуля в этом другом модуле.

Вы можете упростить эту процедуру, используя собственный класс для Mapper вместо обычного dict, и чтобы этот класс работал в своем __getitem__, чтобы посмотреть в «известном месте» (например, прочитать некоторую переменную модуля), чтобы использовать в качестве основы для оценки a. Тем не менее, это будет более тяжелое решение.

Суть заключается в том, что вы просто не можете (опять же, без использования eval или других подобных отверстий) писать код в mapper.py, который использует неопределенную переменная a, а затем определить в другом модуле переменной a и иметь mapper.py автоматически знать об этом. Там должна быть какая-то строка кода, где «говорит» mapper.py какое значение a вы хотите использовать.

0

Я не уверен, что я полностью следовать, но a может "зарегистрировать" это метод с Mapper из любого места, которое содержит ссылку на Mapper:

#mapping.py 
Mapper = {} 

, а затем:

#main.py 
from mapping import Mapper 

#snip 
a = A() 
Mapper['test'] = a.foo #put your instance method into the Mapper dict. 
#snip 

Mapper['test']() 
+0

Нет сожаления, что это не то, что я хочу. Полное определение функции должно быть указано в 'mapper.py' для любого экземпляра' a'. Неизвестно заранее, что такое 'a'. Я буду опрокидываться в вопросе. – Alex

+0

@Alex: Вы не можете ожидать «полного определения», если вы не знаете, что такое объект. В какой-то момент вам нужно будет указать, что это за объект. – BrenBarn

Смежные вопросы