0

PEP 3115有以下使用__prepare__元类方法的示例(print语句是我的):

# The custom dictionary
class member_table(dict):
    def __init__(self):
        self.member_names = []

    def __setitem__(self, key, value):
        print(f'in __setitem__{key, value}')
        # if the key is not already defined, add to the
        # list of keys.
        if key not in self:
            self.member_names.append(key)

        # Call superclass
        dict.__setitem__(self, key, value)

# The metaclass
class OrderedClass(type):

    # The prepare function
    @classmethod
    def __prepare__(metacls, name, bases): # No keywords in this case
        print('in __prepare__')
        return member_table()

    # The metaclass invocation
    def __new__(cls, name, bases, classdict):
        print('in __new__')
        # Note that we replace the classdict with a regular
        # dict before passing it to the superclass, so that we
        # don't continue to record member names after the class
        # has been created.
        result = type.__new__(cls, name, bases, dict(classdict))
        result.member_names = classdict.member_names
        return result

print('before MyClass')

class MyClass(metaclass=OrderedClass):
    print('in MyClass 1')

    # method1 goes in array element 0
    def method1(self):
        pass
    
    print('in MyClass 2')

    # method2 goes in array element 1
    def method2(self):
        pass
    
    print('in MyClass 3')

运行这个,打印这个:

before MyClass
in __prepare__
in __setitem__('__module__', '__main__')
in __setitem__('__qualname__', 'MyClass')
in MyClass 1
in __setitem__('method1', <function MyClass.method1 at 0x7fa70414da60>)
in MyClass 2
in __setitem__('method2', <function MyClass.method2 at 0x7fa70414daf0>)
in MyClass 3
in __new__

所以看起来什么时候MyClass执行,首先执行到类的元类__prepare__方法返回member_table()(谁/什么使用这个返回值?),然后设置类的__module____qualname__,然后执行类体,设置类的方法(method1method2) ,然后__new__调用该方法,并将返回值__prepare__作为classdict参数值__new__(谁/什么传递了这个值?)。


我试图在 thonny 的调试器中逐步执行,但这引发了错误。我还尝试在 pythontutor.com 中逐步执行,但这还不够精细。我pdb'编辑了它,但很难理解发生了什么。最后,我添加了一些print语句,它们出现在上面的代码中。

4

1 回答 1

1

的结果prepare()namespace传递给的参数__new__。它是评估类主体的命名空间(参见 [1])。

因此,在新创建的类中,您可以看到 、 等的值MyClass.__module__MyClass.__qualname__因为它们是在 的命名空间对象中分配的MyClass

元类的大多数用途都不需要prepare(),而是使用普通的命名空间。

[1] https://docs.python.org/3.9/reference/datamodel.html?highlight=__prepare__#preparing-the-class-namespace

于 2021-11-07T06:11:18.887 回答