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

Python 我应该使用元类、类装饰器还是重写_new_____)方法?,python,inheritance,metaclass,Python,Inheritance,Metaclass,这是我的问题。我希望下面的类具有一组属性属性。我可以像foo和bar那样写出它们,或者根据我看到的一些其他示例,看起来我可以使用类装饰器、元类,或者重写\uuuu new\uuuu方法来自动设置属性。我只是不确定什么是“正确”的方法 class Test(object): def calculate_attr(self, attr): # do calculaty stuff return attr @property def foo(s

这是我的问题。我希望下面的类具有一组属性属性。我可以像
foo
bar
那样写出它们,或者根据我看到的一些其他示例,看起来我可以使用类装饰器、元类,或者重写
\uuuu new\uuuu
方法来自动设置属性。我只是不确定什么是“正确”的方法

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')

元类的
\uuuu new\uuuu
不会成为所创建类的
\uuuu new\uuuu
,而是用于创建类本身。实际的类对象由元类返回。类的新实例由
返回

考虑以下(疯狂)代码:

(我使用了一个函数而不是一个类作为元类。任何可调用的函数都可以作为元类使用,但许多人选择将它们的类作为继承自
type
,并重写了new的类。这两个函数之间的区别很微妙。)

它输出

name C
bases ('hello', 'world')
dict {'baz': <function baz at 0x4034c844>, '__module__': '__main__', 'foo': 'bar', '__metaclass__': <function MyMetaClass at 0x40345c34>}
C 7
name C
基地(‘你好’、‘世界’)
dict{'baz':,'uuuuuuuuu模块:'uuuuuuuuuuuuu':'uuuuuuuuuu主','foo':'bar','uuuuuuu元类:}
C7
这是否有助于您更好地理解元类是什么


您很少需要定义自己的元类。

在创建新类(而不是实例)时使用元类。通过这种方式,您可以注册类(django这样做,并使用它在数据库中创建表)。因为
class
是一条指令,你可以把它看作是一个类的装饰器。

魔法是不好的。它使您的代码更难理解和维护。实际上,您根本不需要元类或
\uuuuuuu new\uuuuuu

看起来您的用例可以用非常简单的代码来实现(只需一点点魔力):


当有疑问时,总是用简单和明显的方式。如果你不能很容易地理解它,那么被要求维护你的代码的傻瓜(像我一样)也不能。当你改变问题的性质时,通常最好打开一个新的问题。@你几乎不需要元类或
\uuu new\uuu
:我强烈反对。在我的公司,我们已经有过两次机会,当时我们有很好的动机使用元类。首先是为我们使用的自定义数据库创建抽象层,另一个是为ldap创建我们自己的模型系统。我真的不明白,对元类的怨恨是从哪里来的。这是一个容易理解的概念,在某些情况下非常有用。@gruszczy,元类并不难理解,它们实际上是一个非常简单的概念,尽管Python中元类的语法和用法让一些人遇到了麻烦。然而,由于它们传播的方式,它们容易出错,有时很难组合。即使是完全合理的操作,也不可能自动让一个类在其构造中使用两个元类。元类通常不作为系统公共API的一部分公开,这一事实加剧了这个问题。这不应该是“实际类对象”而不是“实际类对象”吗?我真的很喜欢“类”C现在是“7”。。。直觉的
name C
bases ('hello', 'world')
dict {'baz': <function baz at 0x4034c844>, '__module__': '__main__', 'foo': 'bar', '__metaclass__': <function MyMetaClass at 0x40345c34>}
C 7
class Test(object):
    def calculate_attr(self, attr):
        return something

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