python中的type和type.__new__有啥区别?

Posted

技术标签:

【中文标题】python中的type和type.__new__有啥区别?【英文标题】: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)

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

【问题讨论】:

【参考方案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 应该如何神奇地知道你想要它制作什么样的对象? 好吧,因为我告诉它。我通过了名字、基础和字典。我还需要提供哪些其他信息?

以上是关于python中的type和type.__new__有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

python中的内方法

原创Python 对象创建过程中元类, __new__, __call__, __init__ 的处理

Python元类的__new__方法中的奇怪行为[重复]

Python 在 __new__ 中创建对象期间设置属性

Python面试进阶问题,__init__和__new__的区别是什么?

python如何使用__new__()函数的参数列表中的属性创建类?