Если это ваш код, то решение состоит не в том, чтобы зависеть от переменных уровня модуля, а в другом способе сохранения состояния объектов.Модули в Python являются «синглетонами» - это означает, что после импорта любым модулем существует только одна версия затем, с широким интерпретатором. Например, поведение, которое вам нужно, это именно то, что вы получаете бесплатно, если используете наследование классов.- дочерний класс может настраивать некоторые, но не нужно переписывать все, родительского класса.
Так что, если вы столько же инкапсулируете свой код "foo" внутри класса - вам, возможно, даже не придется писатькласс, которому нужны экземпляры, вы уже получаете нужные вам функции:
#foo module:
class Foo(object):
sanitize = "value 1"
@classmethod
def parse(cls):
print cls.sanitize
#foo2
from foo import Foo
class Foo2(Foo):
sanitize = "value 2"
# code:
from foo import Foo
from foo2 import Foo2
Foo.parse()
Foo2.parse()
Конечно, с большим количеством самоанализа и метапрограммирования, которые позволяет Python, можно сделать возможнымчто-то вроде того, что вы хотите - но это усложнит дело, ни к чему хорошему.Переменные модуля имеют большинство тех же недостатков, что и глобальные переменные в коде C.
Один из способов сделать это - сделать «foo» при доступе через foo2, чтобы сделать переменные на лету, вызвать функцию в"Foo" и восстановить предыдущие значения при выходе.Для запуска произвольного кода при доступе к атрибуту «foo» в модуле «foo2», «foo» должен ссылаться на объект с атрибутом «property» -
Итак, пример exa, который вы написалимежду прочим, будет выполняться небезопасным способом, кстати, очень небезопасно, если foo2 записывается более или менее так:
import foo as _foo
SANITIZE = "value2"
class _FooWrapper(object):
def __getattribute__(self, attr):
self.change_vars()
original_function = getattr(_foo, attr)
if callable(original):
def wrapper(func):
def new_func(*args, **kw):
res = func(*args, **kw)
self.restore_vars()
return res
return new_func
return wrapper(original)
return original
def change_vars(self):
self.original_sanitize = _foo.SANITIZE
_foo.SANITIZE = SANITIZE
def restore_vars(self):
__foo.SANITIZE = self.original_sanitize
foo = _FooWrapper()
Это создает объект "foo" в модуле foo2, который при обращении извлекает любыевместо этого запрошенные атрибуты из исходного модуля "foo".Таким образом, «foo2.foo.parse» получит функцию синтаксического анализа «foo», но при этом учитывает количество «хакерства», чтобы иметь возможность восстановить первоначальное значение в модуле «foo», который находится внутриИнтерпретатор Python, после того, как функция была извлечена из foo2, эта функция, по возвращении, тоже восстанавливает значения.Единственный способ сделать это - изменить функцию так, чтобы она выполняла дополнительный код при возврате - так, чтобы он на лету украшался приведенным выше кодом.
Я думаю, этот пример проясняет, что наличие конфигураций уровня модуляв данном случае это не тот путь, хотя это возможно.
РЕДАКТИРОВАТЬ ОП прокомментировал:
Спасибо jsbueno, к сожалению, это не мой код, и я долженполагаться на переменные уровня модуля.Метод класса Wrapper интересен, но, как вы сказали, очень хакерский и невероятно небезопасный, что, боюсь, не подойдет для моего случая
В ответ на это:
Модули являются "синглетонами" - поэтому изменение переменной в модуле в любой момент сделает его небезопасным.Другой способ, которым я могу думать об этом, - это создание модуля «фотокопировального устройства», который при импорте фактически воссоздает классы, атрибуты и экземпляры другого существующего модуля, связывая все глобальные переменные функций (методы по-прежнему будут доступны как функции на этом уровне).)
Читая это описание, оно может звучать как «неосуществимое» - но это легче сделать, чем описано - здесь следует мой модуль «foo2», который выполняет выше:
from types import ModuleType, FunctionType
import foo as _foo
SANITIZE = "value 2"
def rebuild_function(func, glob):
"""Rebinds the globals in the given functions to globals in
this module by default"""
new_func = FunctionType(func.func_code,
glob,
func.func_name,
func.func_defaults,
func.func_closure)
return new_func
def rebuild_class(cls, glob):
metatype = type(cls)
dct = cls.__dict__.copy()
for key, value in dct.items():
if isinstance(value, FunctionType):
dct[key] = rebuild_function(value, glob)
return metatype(cls.__name__, cls.__bases__, dct)
def rebuild_module(mod,glob):
new_module = ModuleType(mod.__name__)
for key, value in mod.__dict__.items():
if isinstance(value, FunctionType):
value = rebuild_function(value, glob)
elif isinstance(value, type):
value = rebuild_class(value, glob)
setattr(new_module, key, value)
return new_module
foo = rebuild_module(_foo, globals())
__all__ = ["foo", "SANITIZE"]
Этот код делает именно то, что я описал - он воссоздает все функциональные объекты в исходном модуле, переопределяет глобальный dict для каждой функции.Это безопасно для параллелизма.В некоторых угловых случаях потенциальный клонированный модуль указывает на классы или функции нативного кода (они не относятся к «FunctionType»).Если он интенсивно использует наследование нескольких классов, метаклассы, - это может сработать или нет.
Я проверил его с помощью простого класса, и он работал нормально:
#module "foo"
SANITIZE='foo'
def parse():
print SANITIZE
class Parser(object):
def __init__(self):
print SANITIZE * 2
И
#test script
import foo
import foo2
foo2.foo.parse() #i want this to print 'foo2'
foo2.foo.Parser()
foo.parse() #i want this to print 'foo'
foo.Parser()
Вывод:
[gwidion@powerpuff tmp16]$ python test_foo.py
foofoo
value 2
value 2value 2
foo
foofoo
[gwidion@powerpuff tmp16]$