编辑:注意到在生产代码中这是一个非常糟糕的想法。这对我来说是件有趣的事。别在家里这么做!
是否可以修改整个程序的__metaclass__变量(解释器)?
这个简单的例子起作用了:
class ChattyType(type):
def __init__(cls, name, bases, dct):
print "Class init", name
super(ChattyType, cls).__init__(name, bases, dct)
__metaclass__= ChattyType
class Data:
pass
data = Data() # prints "Class init Data"
print data但是我希望能够改变__metaclass__,即使在子模块中也能工作。因此,例如(文件m1.py):
class A:
pass
a=A()
print a文件main.py:
class ChattyType(type):
def __init__(cls, name, bases, dct):
print "Class init", name
super(ChattyType, cls).__init__(name, bases, dct)
__metaclass__= ChattyType
import m1 # and now print "Class init A"
class Data:
pass
data = Data() # print "Class init Data"
print data我理解全局__metaclass__不再在Python3.x中工作,但这不是我关心的问题(如果我的代码是概念的证明的话)。那么在Python-2.x中有什么方法可以做到这一点吗?
发布于 2009-12-02 01:57:00
好吧,这是恶心的,毛茸茸的,黑魔法。您不应该使用它,也许永远使用,但特别是在生产代码中。不过,为了好奇起见,这是一种有趣的现象。
您可以使用佩普302中描述的机制编写自定义导入程序,并在Doug的PyMOTW:模块和导入中进一步讨论。这为您提供了完成您所设想的任务的工具。
我实施这样一个进口商,仅仅是因为我很好奇。本质上,对于您通过类变量__chatty_for__指定的模块,在计算代码之前,它将在导入模块的__dict__中插入自定义类型作为__metaclass__变量。如果所讨论的代码定义了自己的__metaclass__,则将替换导入程序预先插入的代码。在仔细考虑如何处理模块之前,将此进口商应用于任何模块是不可取的。
我没有给很多进口商写信,所以在写这个的时候,我可能做了一个或多个愚蠢的事情。如果有人注意到我在执行过程中遗漏的缺陷/角落案例,请留下评论。
源文件1:
# foo.py
class Foo: pass源文件2:
# bar.py
class Bar: pass源文件3:
# baaz.py
class Baaz: pass而主要活动是:
# chattyimport.py
import imp
import sys
import types
class ChattyType(type):
def __init__(cls, name, bases, dct):
print "Class init", name
super(ChattyType, cls).__init__(name, bases, dct)
class ChattyImporter(object):
__chatty_for__ = []
def __init__(self, path_entry):
pass
def find_module(self, fullname, path=None):
if fullname not in self.__chatty_for__:
return None
try:
if path is None:
self.find_results = imp.find_module(fullname)
else:
self.find_results = imp.find_module(fullname, path)
except ImportError:
return None
(f,fn,(suf,mode,typ)) = self.find_results
if typ == imp.PY_SOURCE:
return self
return None
def load_module(self, fullname):
#print '%s loading module %s' % (type(self).__name__, fullname)
(f,fn,(suf,mode,typ)) = self.find_results
data = f.read()
if fullname in sys.modules:
module = sys.modules[fullname]
else:
sys.modules[fullname] = module = types.ModuleType(fullname)
module.__metaclass__ = ChattyType
module.__file__ = fn
module.__name__ = fullname
codeobj = compile(data, fn, 'exec')
exec codeobj in module.__dict__
return module
class ChattyImportSomeModules(ChattyImporter):
__chatty_for__ = 'foo bar'.split()
sys.meta_path.append(ChattyImportSomeModules(''))
import foo # prints 'Class init Foo'
import bar # prints 'Class init Bar'
import baaz发布于 2009-12-02 01:10:02
Python2的“全局__metaclass__”特性仅用于每个模块的工作(想想看,如果不是这样的话,它会给您自己的元类带来多大的破坏,因为从那时起您导入的所有库和第三方模块都会受到影响!)如果“秘密”改变从某一点开始导入的所有模块的行为是非常重要的,无论出于什么原因,您都可以使用导入钩子玩非常肮脏的把戏(最坏的方法是首先将源复制到临时位置,同时更改它们.)但这一努力将与行为的巨大程度相称,这似乎是适当的;-)
发布于 2009-12-01 22:51:42
不是的。(这是一项功能!)
https://stackoverflow.com/questions/1829205
复制相似问题