关于python 3.x:__new__, __init__, metaclasses,superclasses

__new__, __init__, and metaclasses (and superclasses)

我花了一整天的时间试图理解Python类模型的复杂性,与修饰器、元类和超类混在一起。

目前,我正试图弄清楚某些令牌函数的角色,即新的(这里的背景是元类以及何时/如何调用函数)

我制作了一个新的模拟模块来运行测试,这里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#! /usr/bin/env python3

import sys as system
import os  as operating_system

from functools import partial
from time      import perf_counter as counter

class Meta(type):

    @classmethod
    def __prepare__(instance, name, supers, *list, **map):
        print('{} in meta prepare'.format(name))
        return {}

    def __new__(instance, name, supers, attributes, *list, **map):
        print('{} in meta new'.format(name))
        return instance

    def __init__(self, name, supers, attributes, *list, **map):
            print('{} in meta init'.format(self))

    def __call__(self, *list, **map):
        print('{} in meta call'.format(self))
        return type.__call__(self)
        print('after call')

class Super(object):

    def __new__(instance, *list, **map):
        print('{} in Super new'.format(instance))
        return instance

    def __init__(self, *list, **map):
        print('{} in Super init'.format(self))

    def __call__(self, *list, **map):
        print('{} in Super call'.format(self))
        return object.__call__(self)

class Other(object):

    def __new__(instance, *list, **map):
        print('{} in Other new'.format(instance))
        return instance

    def __init__(self, *list, **map):
        print('{} in Other init'.format(self))

    def __call__(self, *list, **map):
        print('{} in Other call'.format(self))
        return object.__call__(self)

class MetaSuper(object, metaclass = Meta):

    def __new__(instance, *list, **map):
        print('{} in MetaSuper new'.format(instance))
        return instance

    def __init__(self, *list, **map):
        print('{} in MetaSuper init'.format(self))

    def __call__(self, *list, **map):
        print('{} in MetaSuper call'.format(self))
        return object.__call__(self)

class DoubleSuper(Super, MetaSuper):

    def __new__(instance, *list, **map):
        print('{} in DoubleSuper new'.format(instance))
        return instance

    def __init__(self, *list, **map):
        print('{} in DoubleSuper init'.format(self))
        Super.__init__(self, *list, **map)
        MetaSuper.__init__(self, *list, **map)

    def __call__(self, *list, **map):
        print('{} in DoubleSuper call'.format(self))
        return object.__call__(self)

class SuperThenMeta(Super, metaclass = Meta):

    def __new__(instance, *list, **map):
        print('{} in SuperThenMeta new'.format(instance))
        return instance

    def __init__(self, *list, **map):
        print('{} in SuperThenMeta init'.format(self))
        Super.__init__(self, *list, **map)

    def __call__(self, *list, **map):
        print('{} in SuperThenMeta call'.format(self))
        return object.__call__(self)

class Triple(Super, Other, metaclass = Meta):

    def __new__(instance, *list, **map):
        print('{} in Triple new'.format(instance))
        return instance

    def __init__(self, *list, **map):
        print('{} in Triple init'.format(self))
        Super.__init__(self, *list, **map)
        Other.__init__(self, *list, **map)

    def __call__(self, *list, **map):
        print('{} in Triple call'.format(self))
        return object.__call__(self)

class Simple(Super):

    def __new__(instance, *list, **map):
        print('{} in Simple new'.format(instance))
        return instance.__init__(instance, *list, **map)

    def __init__(self, *list, **map):
        print('{} in Simple init'.format(self))
        Super.__init__(self, *list, **map)
        Other.__init__(self, *list, **map)

    def __call__(self, *list, **map):
        print('{} in Simple call'.format(self))
        return object.__call__(self)    

def main():
    #thing = SuperThenMeta()
    #other = DoubleSuper()
    last  = Super()
    simp  = Simple()
    trip  = Triple()

if __name__ == '__main__':
    main()

医生,我在这些工件之间试验了几种不同的设置。

如果我运行这个,这是输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
MetaSuper in meta prepare
MetaSuper in meta new
SuperThenMeta in meta prepare
SuperThenMeta in meta new
Triple in meta prepare
Triple in meta new
<class '__main__.Super'> in Super new
<class '__main__.Simple'> in Simple new
<class '__main__.Simple'> in Simple init
<class '__main__.Simple'> in Super init
<class '__main__.Simple'> in Other init
Traceback (most recent call last):
File"./metaprogramming.py", line 134, in <module>
  main()
File"./metaprogramming.py", line 131, in main
  trip = Triple()
TypeError: __new__() missing 3 required positional arguments: 'name', 'supers', and 'attributes'

由此,我有几个问题:

  • 我是否应该在新函数的末尾调用instance.init(instance,*list,**map)?我不这么认为,但是在"简单"的例子中添加这个似乎是可行的,而"超级"从未达到它的初始值。我的印象是,通过在我自己的调用方法中调用object.call,这将由它的默认实现来处理,但是在整个程序中不会进行任何调用。

  • 为什么首先调用triple()调用元类?如果这是正常的,这是否意味着这是任何具有元类的类的典型情况?这种行为与超类类似吗?

  • 我以为电话会在这个名单上的某个地方。在对象的创建过程中(例如[Prepare]、New、Init),是否不调用它?

我知道这是很多信息,所以感谢您阅读本文,任何指导都将不胜感激。


元类'__new__

方法__new__是创建新实例所调用的方法。因此,它的第一个参数不是和instance,因为还没有创建任何参数,而是类本身。

在元类的情况下,__new__将返回元类的一个实例,即一个类。签名如下:

1
2
3
class Meta(type):
    def __new__(metacls, name, bases, namespace, **kwargs):
        ...
  • metacls是元类本身。

  • name是一个字符串,表示实例化。

  • bases是类将从中继承的类的元组。

  • namespace是类的名称空间,这是对象由__prepare__返回,现在用类属性填充。

  • **kwargs是在实例化时传递给类的任何关键字参数。

要实例化一个类,需要调用type.__new__,这是默认的元类。你通常通过打电话给super().__new__来做到这一点。

1
2
3
4
5
6
7
8
class Meta(type):
    def __new__(metacls, name, bases, namespace, **kwargs):
        print('You can do stuff here')

        cls = super().__new__(metacls, name, bases, namespace, **kwargs)

        # You must return the generated class
        return cls

元类'__init__

__init__方法的行为与其他任何类都没有区别。如果__new__返回一个预期类型的实例,它将在此处接收一个类作为参数创建的实例。在您的示例中,__new__不返回Meta类型的对象。它返回Meta本身,它是type类型。

下面的__init__方法在实例化中从不被调用。

1
2
3
4
5
6
7
class Meta(type):
    def __new__(metacls, name, bases, namespace, **kwargs):
        return None # or anything such that type(obj) is not Meta

    def __init__(self, name, bases, namespace, **kwargs):
        # This will never be called because the return type of `__new__` is wrong
        pass

下面是在实例化时调用的,因为Meta.__new__正确返回Meta类型的对象。

1
2
3
4
5
6
class Meta(type):
        def __new__(metacls, name, bases, namespace, **kwargs):
            return super().__new__(metacls, name, bases, namespace, **kwargs)

        def __init__(self, name, bases, namespace, **kwargs):
            print('__init__ was called')

元类'__call__

同样,__call__的行为与其他任何一类都没有区别。当您试图调用元类的实例时调用它,而当您调用元类创建实例(类)时调用__new____init__

当然,调用一个类应该会返回一个实例,所以不要忘记调用super().__call__并返回其结果,否则会使实例创建短路。

1
2
3
4
5
6
7
8
9
10
11
class Meta(type):
    def __call__(self, *args, **kwargs):
        print(f'An instance was called with {args}')
        return super().__call__(self, *args, **kwargs)

# This declaration if what calls __new__ and __init__ of the metaclass
class Klass(metaclass=Meta):
    pass

# This calls the __call__ method of the metaclass
instance = Klass()