代码之家  ›  专栏  ›  技术社区  ›  Muhammad Alkarouri

什么时候在Python中内联元类的定义?

  •  15
  • Muhammad Alkarouri  · 技术社区  · 15 年前

    here

    class Plugin(object):
        class __metaclass__(type):
            def __init__(cls, name, bases, dict):
                type.__init__(name, bases, dict)
                registry.append((name, cls))
    

    什么时候使用这样的内联定义才有意义?

    进一步论证:

    a conservative metaclass 定义

    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
    

    可以写成

    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
    

    1 回复  |  直到 15 年前
        1
  •  20
  •   martineau    13 年前

    基本上,不是给元类一个正确的顶级名称,而是让在模块中定义的所有自定义元类根据它们的属性彼此不可区分 __module__ __name__ 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__'>
    

    Mcl 在主模块中。然而,如果您想检查“哪种类型是class 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__'
    >>> 
    

    ……在那里 事实上,没有这样的事;那个repr是误导性的,并不是很有帮助;-)。

    类的repr本质上是 '%s.%s' % (c.__module__, c.__name__) --一个简单、有用且一致的规则——但在许多情况下,例如 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
    

    有两个 语句,第二个语句重新绑定名称(这里, A ),但现有实例引用的是按对象而不是按名称的名称的第一个绑定——因此两个类对象都保留,一个只能通过 type (或 __class__ 类型 ),如果需要调试或自省,可能会引起类似的混乱。

    因此,如果您不需要调试或以其他方式反省代码,嵌套元类是可以的,并且如果这样做的人理解这个怪癖,就可以与之一起生活(当然,它永远不会像使用一个好的、真实的名称那样方便——就像调试一个用 lambda def ). 以此类推 λ 定义 您可以合理地宣称,对于元类来说,匿名的“嵌套”定义是可以的,因为元类非常简单,非常容易理解,因此不需要调试或自省。

    class A(metaclass=Mcl): ,所以定义 在体内没有作用。我相信这也表明,只有当您确信代码永远不需要被移植到Python3时,在Python2代码中嵌套的元类定义才可能是合适的(因为您正在使移植变得更加困难,并且为此需要取消元类定义的嵌套)——“一次性”代码,换句话说,当某些版本的python3在速度、功能或第三方支持方面获得了巨大的、引人注目的优势,而不是python2.7(python2的最后一个版本)时,这种优势将不会在几年内出现。

    你的代码 期待