首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >修改整个程序的__metaclass__

修改整个程序的__metaclass__
EN

Stack Overflow用户
提问于 2009-12-01 21:55:05
回答 3查看 899关注 0票数 2

编辑:注意到在生产代码中这是一个非常糟糕的想法。这对我来说是件有趣的事。别在家里这么做!

是否可以修改整个程序的__metaclass__变量(解释器)?

这个简单的例子起作用了:

代码语言:javascript
复制
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):

代码语言:javascript
复制
 class A:
       pass

 a=A()
 print a

文件main.py:

代码语言:javascript
复制
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中有什么方法可以做到这一点吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-12-02 01:57:00

好吧,这是恶心的,毛茸茸的,黑魔法。您不应该使用它,也许永远使用,但特别是在生产代码中。不过,为了好奇起见,这是一种有趣的现象。

您可以使用佩普302中描述的机制编写自定义导入程序,并在Doug的PyMOTW:模块和导入中进一步讨论。这为您提供了完成您所设想的任务的工具。

我实施这样一个进口商,仅仅是因为我很好奇。本质上,对于您通过类变量__chatty_for__指定的模块,在计算代码之前,它将在导入模块的__dict__中插入自定义类型作为__metaclass__变量。如果所讨论的代码定义了自己的__metaclass__,则将替换导入程序预先插入的代码。在仔细考虑如何处理模块之前,将此进口商应用于任何模块是不可取的。

我没有给很多进口商写信,所以在写这个的时候,我可能做了一个或多个愚蠢的事情。如果有人注意到我在执行过程中遗漏的缺陷/角落案例,请留下评论。

源文件1:

代码语言:javascript
复制
# foo.py
class Foo: pass

源文件2:

代码语言:javascript
复制
# bar.py
class Bar: pass

源文件3:

代码语言:javascript
复制
# baaz.py
class Baaz: pass

而主要活动是:

代码语言:javascript
复制
# 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
票数 4
EN

Stack Overflow用户

发布于 2009-12-02 01:10:02

Python2的“全局__metaclass__”特性仅用于每个模块的工作(想想看,如果不是这样的话,它会给您自己的元类带来多大的破坏,因为从那时起您导入的所有库和第三方模块都会受到影响!)如果“秘密”改变从某一点开始导入的所有模块的行为是非常重要的,无论出于什么原因,您都可以使用导入钩子玩非常肮脏的把戏(最坏的方法是首先将源复制到临时位置,同时更改它们.)但这一努力将与行为的巨大程度相称,这似乎是适当的;-)

票数 7
EN

Stack Overflow用户

发布于 2009-12-01 22:51:42

不是的。(这是一项功能!)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1829205

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档