今天,我所遇到的Python元类的一个令人惊讶的定义在这里,与元类定义有效的内联.相关部分是
class Plugin(object):
class __metaclass__(type):
def __init__(cls, name, bases, dict):
type.__init__(name, bases, dict)
registry.append((name, cls))
Run Code Online (Sandbox Code Playgroud)
什么时候使用这样的内联定义是有意义的?
进一步的论点:
一种方式的论点是创建的元类在其他地方使用这种技术是不可重用的.一个反驳论点是,使用元类的一个常见模式是定义元类并在一个类中使用它,然后从中继承.例如,在保守的元类中定义
class DeclarativeMeta(type):
def __new__(meta, class_name, bases, new_attrs):
cls = type.__new__(meta, class_name, bases, new_attrs)
cls.__classinit__.im_func(cls, new_attrs)
return cls
class Declarative(object):
__metaclass__ = DeclarativeMeta
def __classinit__(cls, new_attrs): pass
Run Code Online (Sandbox Code Playgroud)
本来可以写成
class Declarative(object): #code not tested!
class __metaclass__(type):
def __new__(meta, class_name, bases, new_attrs):
cls = type.__new__(meta, class_name, bases, new_attrs)
cls.__classinit__.im_func(cls, new_attrs)
return cls
def __classinit__(cls, new_attrs): pass
Run Code Online (Sandbox Code Playgroud)
还有其他考虑吗?
Ale*_*lli 19
像其他形式的嵌套类定义一样,嵌套的元类可能更"紧凑和方便"(只要你没有重用除了继承之外的那个元类)用于多种"生产用途",但可以在某种程度上不方便调试和内省.
基本上,而不是给元类适当的,顶级的名字,你会用一个模块中定义的所有自定义元类是相互undistiguishable基础上,结束了自己__module__和__name__属性(这是Python的使用,以形成自己的repr,如果需要).考虑:
>>> class Mcl(type): pass
...
>>> class A: __metaclass__ = Mcl
...
>>> class B:
... class __metaclass__(type): pass
...
>>> type(A)
<class '__main__.Mcl'>
>>> type(B)
<class '__main__.__metaclass__'>
Run Code Online (Sandbox Code Playgroud)
IOW,如果你想检查"哪个类型是A类"(元类是类的类型,请记住),你会得到一个明确而有用的答案 - 它Mcl在主模块中.但是,如果要检查"这类型是B类",得到的回答是不是所有的有用:它说,它__metaclass__的在main模块,但是这不是真的:
>>> import __main__
>>> __main__.__metaclass__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute '__metaclass__'
>>>
Run Code Online (Sandbox Code Playgroud)
...有是没有这样的事,实际上,那个repr是误导性的,不是很有帮助;-).
类的repr本质上是'%s.%s' % (c.__module__, c.__name__)一个简单,有用且一致的规则 - 但在许多情况下,例如,class语句在模块范围内不是唯一的,或者根本不在模块范围内(而是在函数或类体内) ),或者甚至不存在(类当然可以在没有class语句的情况下通过显式调用它们的元类来构建),这可能有些误导(并且最好的解决方案是尽可能避免那些特殊情况,除非通过使用它们可以获得实质性的优点).例如,考虑:
>>> class A(object):
... def foo(self): print('first')
...
>>> x = A()
>>> class A(object):
... def foo(self): print('second')
...
>>> y = A()
>>> x.foo()
first
>>> y.foo()
second
>>> x.__class__
<class '__main__.A'>
>>> y.__class__
<class '__main__.A'>
>>> x.__class__ is y.__class__
False
Run Code Online (Sandbox Code Playgroud)
class在同一范围内使用两个语句,第二个重新绑定名称(此处A),但现有实例引用名称的第一个绑定,而不是名称 - 因此两个类对象都保留,一个只能通过type(或其__class__属性实例(如果有的话 - 如果没有,则第一个对象消失) - 这两个类具有相同的名称和模块(因此表示相同),但它们是不同的对象.嵌套在类或函数体中的类,或者通过直接调用元类(包括type)创建的类,如果需要调试或内省,可能会引起类似的混淆.
因此,如果您永远不需要调试或以其他方式反省代码,那么嵌套元类是可以的,并且如果这样做的人理解这个怪癖就可以生活(尽管它永远不会像使用漂亮的真实名称那样方便,当然 - 就像调试一个编码的函数一样,lambda不可能像调试一个编码的那样方便def.通过与lambdavs的类比,def你可以合理地声称匿名的"嵌套"定义对于非常简单的元类来说是可以的,例如毫无疑问,不需要调试或内省.
在Python 3中,"嵌套定义"不起作用 - 在那里,元类必须作为关键字参数传递给类class A(metaclass=Mcl):,因此__metaclass__在主体中定义没有任何效果.我相信这也表明Python 2代码中的嵌套元类定义可能只有在您确定代码永远不需要移植到Python 3时才适用(因为您使端口变得更加困难,并且需要为此目的解析元类定义 - 换句话说,当一些版本的Python 3获得速度,功能或第三方的巨大,引人注目的优势时,它将在几年后出现.派对支持,通过Python 2.7(Python 2的最后一个版本).
正如计算机的历史向我们展示的那样,你期望随时抛出的代码有一种让人惊讶的习惯,并且大约在20年后仍然存在(可能是你在同一时间写的"代码"的代码完全是完全的)忘记了;-).这肯定会建议避免使用嵌套的元类定义.