我应该使用类元、类装饰器还是重写__new__方法?

6 投票
3 回答
2465 浏览
提问于 2025-04-15 20:46

这是我的问题。我想让这个类有很多属性。我要么像foobar那样一个一个写出来,要么根据我看到的一些其他例子,似乎可以用类装饰器、 metaclass(元类)或者重写__new__方法来自动设置这些属性。不过我不太确定哪种方法才是“正确”的做法。

class Test(object):
    def calculate_attr(self, attr):
        # do calculaty stuff
        return attr

    @property
    def foo(self):
        return self.calculate_attr('foo')

    @property
    def bar(self):
        return self.calculate_attr('bar')

3 个回答

1

元类是在创建新类的时候使用的,而不是在创建类的实例时。通过这种方式,你可以注册类(比如Django就是这么做的,它用元类来创建数据库中的表)。因为class可以被看作是一个类的装饰器,所以你可以把它想象成一种特殊的指令。

3

元类的 __new__ 方法并不是用来创建你所定义的类的 __new__ 方法,而是用来创建这个类本身的。元类会返回一个实际的类对象。而类的实例是通过 __new__ 方法返回的。

看看下面这段(疯狂的)代码:

def MyMetaClass(name, bases, dict):
    print "name", name
    print "bases", bases
    print "dict", dict
    return 7

class C('hello', 'world'):
    __metaclass__ = MyMetaClass

    foo = "bar"

    def baz(self, qux):
        pass

print "C", C

(我用一个函数代替了类作为元类。其实任何可以调用的东西都可以当作元类,但很多人选择把自己的元类写成继承自 type 的类,并重写 __new__ 方法。两者之间的区别很微妙。)

它的输出是:

name C
bases ('hello', 'world')
dict {'baz': <function baz at 0x4034c844>, '__module__': '__main__', 'foo': 'bar', '__metaclass__': <function MyMetaClass at 0x40345c34>}
C 7

这样能帮助你更好地理解元类是什么吗?

很少需要自己定义一个元类。

5

魔法是不好的。它会让你的代码变得更难理解和维护。你几乎不需要用到元类或者 __new__ 这些东西。

看起来你的需求可以用相对简单的代码来实现(只需要一点点“魔法”):

class Test(object):
    def calculate_attr(self, attr):
        return something

    def __getattr__(self, name):
        return self.calculate_attr(name)

撰写回答