Python中的元类:需要澄清的几个问题

Red*_*Red 5 python metaprogramming metaclass

在使用元类崩溃之后,我深入研究了Python中元编程的主题,我有几个问题,即imho,在可用的文档中没有明确的答案.

  1. 当同时使用__new__,并__init__在元类,它们的参数必须定义相同?
  2. __init__在元类中定义类的最有效方法是什么?
  3. 有没有办法在元类中引用类实例(通常是self)?

Ros*_*ron 1

对于 1:任何类的__init__和都必须接受相同的参数,因为它们将使用相同的参数进行调用。通常采用更多它忽略的参数(例如,采用任何参数并忽略它们),以便在继承过程中不必覆盖它们,但通常只有在根本没有参数时才这样做。__new____new__object.__new____new____new__

这在这里不是问题,因为正如前面所说,元类总是使用相同的参数集来调用,因此您不会遇到麻烦。至少有论据。但是,如果您要修改传递给父类的参数,则需要同时修改它们。

对于 2:您通常不在__init__元类中定义该类。您可以编写一个包装器并替换元类__init__中的类的,也可以在元类上重新定义 。如果您使用继承,前者会表现得很奇怪。__new____init____call__

import functools

class A(type):
    def __call__(cls, *args, **kwargs):
        r = super(A, cls).__call__(*args, **kwargs)
        print "%s was instantiated" % (cls.__name__, )
        print "the new instance is %r" % (r, )
        return r


class B(type):
    def __init__(cls, name, bases, dct):
        super(B, cls).__init__(name, bases, dct)
        if '__init__' not in dct:
            return
        old_init = dct['__init__']
        @functools.wraps(old_init)
        def __init__(self, *args, **kwargs):
            old_init(self, *args, **kwargs)
            print "%s (%s) was instantiated" % (type(self).__name__, cls.__name__)
            print "the new instance is %r" % (self, )
        cls.__init__ = __init__


class T1:
    __metaclass__ = A

class T2:
    __metaclass__ = B
    def __init__(self): 
        pass

class T3(T2):
    def __init__(self):
        super(T3, self).__init__()
Run Code Online (Sandbox Code Playgroud)

调用它的结果:

>>> T1()
T1 was instantiated
the new instance is <__main__.T1 object at 0x7f502c104290>
<__main__.T1 object at 0x7f502c104290>
>>> T2()
T2 (T2) was instantiated
the new instance is <__main__.T2 object at 0x7f502c0f7ed0>
<__main__.T2 object at 0x7f502c0f7ed0>
>>> T3()
T3 (T2) was instantiated
the new instance is <__main__.T3 object at 0x7f502c104290>
T3 (T3) was instantiated
the new instance is <__main__.T3 object at 0x7f502c104290>
<__main__.T3 object at 0x7f502c104290>
Run Code Online (Sandbox Code Playgroud)

对于 3:是的,__call__如上所示。