我应该使用元类、类装饰器还是重写 __new__ 方法?
Posted
技术标签:
【中文标题】我应该使用元类、类装饰器还是重写 __new__ 方法?【英文标题】:Should I use a metaclass, class decorator, or override the __new__ method? 【发布时间】:2011-01-31 00:19:15 【问题描述】:这是我的问题。我希望下面的类有一堆属性。我可以像foo
和bar
一样将它们全部写出来,或者根据我见过的其他一些示例,看起来我可以使用类装饰器、元类或覆盖__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')
【问题讨论】:
如有疑问,请始终使用简单明了的方法。如果你不能轻易地弄清楚它,那么将被要求维护你的代码的傻瓜(比如我)也不能。 当您改变问题的性质时,通常最好只打开一个新问题。 【参考方案1】:元类的__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
并覆盖新的类。两者之间的区别功能很微妙。)
输出
name C
bases ('hello', 'world')
dict 'baz': <function baz at 0x4034c844>, '__module__': '__main__', 'foo': 'bar', '__metaclass__': <function MyMetaClass at 0x40345c34>
C 7
这是否有助于您更好地理解元类是什么?
您将很少需要定义自己的元类。
【讨论】:
不应该是“实际类对象”而不是“实际类对象”吗? 我真的很喜欢“类”C 现在是“7”...直观【参考方案2】:魔法不好。它使您的代码更难理解和维护。您几乎不需要元类或__new__
。
看起来你的用例可以用非常简单的代码来实现(只有一点点魔法):
class Test(object):
def calculate_attr(self, attr):
return something
def __getattr__(self, name):
return self.calculate_attr(name)
【讨论】:
@你几乎不需要元类或__new__
:我非常不同意。在我的公司,我们已经有过两次使用元类的动机。首先是为我们使用的自定义数据库创建抽象层,另一个是为 ldap 创建我们自己的模型系统。我真的不明白,这种对元类的怨恨从何而来。这是一个容易掌握的概念,在某些情况下非常有用。
@gruszczy,元类并不难理解,它们实际上是一个非常简单的想法,尽管它们在 Python 中的语法和用法让一些人感到麻烦。然而,由于它们的传播方式,它们很容易出错,并且有时难以组合——即使这是一个完全合理的操作,也不能自动让一个类在其构造中使用两个元类。元类通常不作为系统公共 API 的一部分公开,这一事实加剧了这个问题。【参考方案3】:
在创建新类而不是实例时使用元类。通过这种方式,您可以例如注册类(django 会这样做并使用它例如在数据库中创建表)。由于class
是一条指令,您可以将其视为类的装饰器。
【讨论】:
以上是关于我应该使用元类、类装饰器还是重写 __new__ 方法?的主要内容,如果未能解决你的问题,请参考以下文章