【问题标题】:What is the difference between type and type.__new__ in python?python中的type和type.__new__有什么区别?
【发布时间】:2011-02-06 05:06:59
【问题描述】:

我正在编写一个元类,不小心这样做了:

class MetaCls(type):
    def __new__(cls, name, bases, dict):
        return type(name, bases, dict)

...而不是这样:

class MetaCls(type):
    def __new__(cls, name, bases, dict):
        return type.__new__(cls, name, bases, dict)

这两个元类之间到底有什么区别?更具体地说,是什么导致第一个不能正常工作(元类没有调用某些类)?

【问题讨论】:

    标签: python types new-operator metaclass


    【解决方案1】:

    在第一个示例中,您正在创建一个全新的类:

    >>> class MetaA(type):
    ...     def __new__(cls, name, bases, dct):
    ...         print 'MetaA.__new__'
    ...         return type(name, bases, dct)
    ...     def __init__(cls, name, bases, dct):
    ...         print 'MetaA.__init__'
    ... 
    >>> class A(object):
    ...     __metaclass__ = MetaA
    ... 
    MetaA.__new__
    >>> 
    

    而在第二种情况下,您正在调用父母的__new__

    >>> class MetaA(type):
    ...     def __new__(cls, name, bases, dct):
    ...         print 'MetaA.__new__'
    ...         return type.__new__(cls, name, bases, dct)
    ...     def __init__(cls, name, bases, dct):
    ...         print 'MetaA.__init__'
    ... 
    >>> class A(object):
    ...     __metaclass__ = MetaA
    ... 
    MetaA.__new__
    MetaA.__init__
    >>> 
    

    【讨论】:

    • 对于 python3 class A(object, metaclass=MetaA): pass。 A 类作用域中的 __metaclass__ 被完全忽略
    【解决方案2】:

    请参考下面的注释,希望对您有所帮助。

    class MetaCls(type):
        def __new__(cls, name, bases, dict):
            # return a new type named "name",this type has nothing
            # to do with MetaCls,and MetaCl.__init__ won't be invoked
            return type(name, bases, dict)
    
    class MetaCls(type):
        def __new__(cls, name, bases, dict):
            # return a new type named "name",the returned type 
            # is an instance of cls,and cls here is "MetaCls", so 
            # the next step can invoke MetaCls.__init__ 
            return type.__new__(cls, name, bases, dict)
    

    【讨论】:

      【解决方案3】:

      您首先需要弄清楚object.__new__() 的工作原理。

      这是来自下面的documentation

      object.__new__(cls[, ...])

      调用以创建类cls 的新实例。 __new__() 是静态的 方法(特殊情况,所以你不需要这样声明) 请求实例作为其第一个参数的类。 其余参数是传递给对象构造函数的参数 表达式(对类的调用)。 __new__()的返回值 应该是新的对象实例(通常是cls 的实例)。

      典型的实现通过调用来创建类的新实例 超类的 __new__() 方法使用 super(currentclass, cls).__new__(cls[, ...]) 和适当的参数,然后修改 在返回之前根据需要将新创建的实例。

      如果__new__()返回cls的实例,那么新实例的__init__()方法将像__init__(self[, ...])一样被调用,其中self是新实例,其余参数与 已传递给__new__()

      如果__new__() 没有返回cls 的实例,则不会调用新实例的__init__() 方法。

      __new__() 主要是为了允许不可变 类型的子类(如intstrtuple)自定义实例创建。也是 通常在自定义元类中被覆盖以自定义类 创作。

      所以在mg.的answer中,前者不调用函数__init__,而后者在调用__new__后调用函数__init__

      【讨论】:

      • type.__new__object.__new__ 有什么关系?我没有得到那部分。
      • OP 询问的是 type.__new__(它创建了一个类),而不是 object.__new__(它创建了一个类的实例)。
      • 请参阅有关类类型(对象)docs.python.org/3/library/functions.html?highlight=type#type 的文档,我认为这可能是 type.__new__ 和 object.__new__ 之间的关系。如果你明白了,请记住删除你的反对票,谢谢!
      • 所有你(@Nishant,@rlat) 需要弄清楚的是 Python 的类型和对象是什么,这是答案 cs.utexas.edu/~cannata/cs345/Class%20Notes/… ;所以与object.__new__相关的type.__new__没有区别。
      【解决方案4】:
      return type(name, bases, dict)
      

      您从中得到的是一个新的type,而不是一个MetaCls 实例。因此,您在MetaCls(包括__init__)中定义的方法永远无法被调用。

      type.__new__ 将作为创建新类型的一部分被调用,是的,但是进入该函数的 cls 的值将是 type 而不是 MetaCls

      【讨论】:

        【解决方案5】:
        class MyMeta(type):
            def __new__(meta, cls, bases, attributes):
                print 'MyMeta.__new__'
                return type.__new__(meta, cls, bases, attributes)
            def __init__(clsobj, cls, bases, attributes):
                print 'MyMeta.__init__'
        
        class MyClass(object):
          __metaclass__ = MyMeta
          foo = 'bar'
        

        实现相同结果的另一种方法:

        cls = "MyClass"
        bases = ()
        attributes = {'foo': 'bar'}
        MyClass = MyMeta(cls, bases, attributes)
        

        MyMeta 是可调用的,因此 Python 将使用特殊方法 __call__

        Python 将在 MyMeta 的类型中查找 __call__(在我们的例子中是 type

        "对于新式类,特殊方法的隐式调用是 只有在对象类型上定义时才能保证正常工作,而不是 在对象的实例字典中”

        MyClass = MyMeta(...) 被解释为:

        my_meta_type = type(MyMeta)
        MyClass = my_meta_type.__call__(MyMeta, cls, bases, attributes)
        

        type.__call__() 里面我想像这样:

        MyClass = MyMeta.__new__(MyMeta, cls, bases, attributes)
        meta_class = MyClass.__metaclass__
        meta_class.__init__(MyClass, cls, bases, attributes)
        return MyClass
        

        MyMeta.__new__() 将决定MyClass 的构建方式:

        type.__new__(meta, cls, bases, attributes) 将为MyClass 设置正确的元类(即MyMeta

        type(cls, bases, attributes) 将为MyClass 设置默认元类(即类型)

        【讨论】:

        • cls = "MyClass" 非常具有误导性...cls 通常按惯例表示类实例。但这里你的意思是类名。
        【解决方案6】:

        这一切都描述得很好here

        如果您没有返回正确类型的对象,那么定义自定义元类是没有意义的。

        【讨论】:

        • 但这就是我要解决的问题:为什么type 不返回正确类型的对象?我知道我必须使用子类的__new__ 方法,但这与使用type 有什么不同?
        • type 应该如何神奇地知道你想要它制作什么样的对象?
        • 好吧,因为我告诉它。我通过了名字、基础和字典。我还需要提供哪些其他信息?
        猜你喜欢
        • 2015-04-15
        • 1970-01-01
        • 1970-01-01
        • 2015-07-17
        • 2017-09-14
        • 2016-03-24
        • 2020-11-14
        • 1970-01-01
        相关资源
        最近更新 更多