【问题标题】:How is the .__new__function working in this example?.__new__ 函数在这个例子中是如何工作的?
【发布时间】:2020-07-17 16:12:23
【问题描述】:

我在理解 .new 魔术方法如何创建类时遇到了一些麻烦。下面是我使用的 API 示例,它使用元类从数据库中的信息动态创建对象。

class Metaclass(type):
    def __new__(cls, name, bases, dict_):
        print(f' cls - {cls}')
        print(f' name - {name}')
        print(f' bases - {bases}')
        return super(Metaclass, cls).__new__(cls, name, bases, dict_)

class MyObject(object, metaclass=Metaclass):
    pass

class PrimaryObject(MyObject):
    pass

class SecondaryObject(MyObject):
    pass

test = PrimaryObject()

运行此代码会导致 PrimaryObject 被实例化,它继承自 MyObject,而 MyObject 又继承自元类。然后调用元类中的新魔法方法,该方法对从元类继承的所有对象进行迭代 3 次,甚至包括未调用的对象:

<class '__main__.Metaclass'>
MyObject
(<class 'object'>,)
<class '__main__.Metaclass'>
PrimaryObject
(<class '__main__.MyObject'>,)
<class '__main__.Metaclass'>
SecondaryObject
(<class '__main__.MyObject'>,)
<__main__.PrimaryObject object at 0x000002214A6786D0>

new 方法如何接收这些参数,因为没有任何东西传递给它?它们是从调用它的对象中解析出来的吗?如果是这样,它为什么以及如何迭代从该对象继承但未实例化的其他对象(SecondaryObject)?

谢谢

【问题讨论】:

  • 它是一个元类,它在创建时调用,而不是在创建实例时调用。
  • @jonrsharpe 我认为使用术语“定义”而不是“创建”会更好,即“类已定义”
  • @DeepSpace 不确定是什么让它最清晰,但此时正在创建类型类的实例。
  • MyObjectMetaClass实例;查看type(MyObject) 的值,与type(int) 之类的值相比。

标签: python python-3.x class metaclass


【解决方案1】:

"...它又继承自元类..."

这是您假设中的错误部分。 这些类都不是从元类“继承”的。

元类用于构建它们 - 类本身 - 只需一次 对于每个班级。这就是调用__new__ 的时间:当Python 执行class 语句(以及类主体)时。

实例化PrimaryObject 将不再调用元类__new__ - 只需在test = ... 行之前添加另一个打印语句,您就会看到这一点。

但是,如果您希望在创建使用元类创建的类的实例时调用元类上的方法,那就是__call__ 方法,而不是__new__。当您在元类调用中调用 super().__call__(...) 时,它会运行 type.__call__,而这又会运行类 __new____init__ 方法,创建一个新实例。

print("defining the metaclass")

class Metaclass(type):
    def __new__(cls, name, bases, dict_):
        print(f' cls - {cls}')
        print(f' name - {name}')
        print(f' bases - {bases}')
        return super(Metaclass, cls).__new__(cls, name, bases, dict_)
    def __call__(cls, *args, **kw):
        print(f"Creating a new instance of {cls.__name__}")
        return super().__call__(*args, **kw)

print("Creating the classes that use the metaclass")

class MyObject(object, metaclass=Metaclass):
    pass

class PrimaryObject(MyObject):
    pass

class SecondaryObject(MyObject):
    pass

print("Creating a class instance")

test = PrimaryObject()

【讨论】:

    【解决方案2】:

    元类是类的类型。给定您的代码,比较

    >>> type(MyObject)
    <class '__main__.Metaclass'>
    >>> type(int)
    <class 'type'>
    

    最终,所有元类都继承自type


    class 语句是用于对某些元类进行隐式调用的构造。

    # A = type('A', (), {})
    class A:
        pass
    
    # MyObject = Metaclass('MyObject', (), {})
    class MyObject(metaclass=Metaclass):
        pass
    

    How the metaclass is chosen 在 Python 语言参考中进行了概述。


    像所有类型一样,对类型本身的调用会调用对其__new__方法的调用,所以

    MyObject = Metaclass('MyObject', (), {})
    

    大致相当于

    MyObject = Metaclass.__new__(Metaclass, 'MyObject', (), {})
    if isinstance(MyObject, Metaclass):
        MyObject.__init__()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-05
      • 2017-11-26
      • 2021-10-14
      • 2021-10-05
      • 1970-01-01
      • 2014-10-22
      相关资源
      最近更新 更多