9

我编写了一个元类,用于在我的 python 项目中进行日志记录。它使每个班级自动记录所有活动。唯一的问题是我不想进入每个文件并且必须添加:

__metaclass__ = myMeta

有没有办法在顶级文件夹中设置元类,以便下面的所有文件都使用该元类?

4

2 回答 2

8

不可以,您只能为每个类或每个模块指定元类。您不能为整个包设置它。

在 Python 3.1 及更高版本中,您可以拦截builtins.__build_class__钩子并以编程方式插入元类,请参阅在 Python 运行之前覆盖默认的 type() 元类

在 Python 2.7 中,您可以替换__builtins__.object为使用您的元类的子类。就像builtins.__build_class__钩子一样,这是高级骇客,破坏你的代码就像让你的元类无处不在。

通过替换模块object上的引用来做到这一点:__builtin__

import __builtin__


class MetaClass(type):
    def __new__(mcls, name, *args):
        # do something in the metaclass
        return super(MetaClass, mcls).__new__(mcls, name, *args)


orig_object = __builtin__.orig_object


class metaobject(orig_object):
    __metaclass__ = MetaClass


def enable():
    # *replace* object with one that uses your metaclass
    __builtin__.object = metaobject

def disable():
    __builtin__.object = orig_object

在导入你的包之前运行enable()它,所有新样式的类(那些可以支持元类的)都会有你的元类。请注意,当您的包导入代码时,此行为现在将传播到所有尚未加载的 Python 代码,包括标准库。您可能想使用:

enable()
import package
disable()

来限制效果。

于 2013-04-23T20:27:34.757 回答
1

这是一个简单的技术。只需使用类中的属性对本身进行子类化。__metaclass__这个过程可以自动化。

实用程序.py

class A(object):
    def __init__(self, first, second):
        self.first = first
        self.second = second

    def __str__(self):
        return '{} {}'.format(self.first, self.second)

主文件

from datetime import datetime
from util import A

def meta(*args):
    cls = type(*args)
    setattr(cls, 'created', datetime.now().ctime())
    return cls

try:
    print(A.created)
except AttributeError as e:
    print(e)

class A(A):
    __metaclass__ = meta

print(A.created, str(A('Michael', 'Jackson')))

测试;

$ python main.py 
type object 'A' has no attribute 'created'
('Wed Mar  9 22:58:16 2016', 'Michael Jackson')
于 2016-03-09T17:31:27.080 回答