如果这是你的代码,那么解决方案不是依赖于模块级变量,而是以其他方式保持对象的状态。 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 代码中的全局变量具有大部分相同的缺点。
一种方法是在通过 foo2 访问时使“foo”动态更改变量,在“foo”中调用函数并在退出时恢复先前的值。
对于要在模块“foo2”上的“foo”属性访问时触发任意代码,“foo”必须引用具有“property”属性的对象--
因此,如果 foo2 或多或少这样编写,您编写的 exa 示例将以并发不安全的方式运行,顺便说一句,非常不安全:
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()
这会在模块 foo2 中创建一个“foo”对象,当访问该对象时,它会从原始“foo”模块中检索任何请求的属性。所以“foo2.foo.parse”将获得“foo”解析函数——但是,在这种方法中感知“hackiness”的数量——以便能够恢复位于内部的“foo”模块中的原始值Python 解释器,在从 foo2 获取函数后,该函数也有在返回时恢复值本身。这样做的唯一方法是修改函数,使其在返回时运行附加代码 - 因此它被上面的代码动态修饰。
我认为这个例子清楚地表明,在这种情况下,模块级配置不是可行的方法,尽管可能。
编辑
OP评论:
感谢 jsbueno,很遗憾这不是我的代码,我必须依赖
模块级变量。 Wrapper 类方法很有趣
但正如你所说,非常hacky和令人难以置信的非线程安全,我是
恐怕对我的案子没用
回复:
模块是“单例” - 因此,更改模块上的变量,在
任何一点都会使其线程不安全。我能想到的另一种方式
这是创建一个“复印机”模块,它实际上是重新创建
另一个现有模块的类、属性和实例,当
导入 - 重新绑定所有函数全局变量(方法将
仍可作为此级别的函数访问)
阅读此描述可能听起来“不可行” - 但它比描述更容易 -
下面是执行上述操作的“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"]
这段代码完全符合我的描述 - 它重新创建原始模块中的所有函数对象,重新绑定每个函数的全局字典。它是并发安全的。如果要克隆的模块确实指向本机代码类或函数(它们不是“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]$