python中类型和类型.__ new__有什么区别?

Jas*_*ker 15 python types metaclass new-operator

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

class MetaCls(type):
    def __new__(cls, name, bases, dict):
        return type(name, bases, dict)
Run Code Online (Sandbox Code Playgroud)

......而不是像这样:

class MetaCls(type):
    def __new__(cls, name, bases, dict):
        return type.__new__(cls, name, bases, dict)
Run Code Online (Sandbox Code Playgroud)

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

mg.*_*mg. 9

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

>>> 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__
>>> 
Run Code Online (Sandbox Code Playgroud)

而在第二种情况下,你正在呼叫父母的__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__
>>> 
Run Code Online (Sandbox Code Playgroud)

  • 对于 python3 `class A(object, metaclass=MetaA): pass`。A 类作用域中的 `__metaclass__` 被完全忽略 (2认同)

小智 8

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

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)
Run Code Online (Sandbox Code Playgroud)


pol*_*527 7

你需要弄清楚的第一件事是如何object.__new__()工作.

这是来自文档:

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

被调用来创建一个新的类实例cls.__new__()是一个静态方法(特殊的,因此您不需要声明它),它将请求实例的类作为其第一个参数.其余参数是传递给对象构造函数表达式的参数(对类的调用).返回值__new__() 应该是新的对象实例(通常是实例cls).

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

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

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

__new__()主要是用来允许的子类不可变的类型(如int,strtuple)来定制实例创建.它也通常在自定义元类中重写,以自定义类创建.

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

  • `type .__ new__`与`object .__ new__`有什么关系?我没有得到那个部分. (2认同)
  • 您(@ Nishant,@ rlat)需要弄清楚的是什么是Python的类型和对象,这是答案http://www.cs.utexas.edu/~cannata/cs345/Class%20Notes/15%20Python% 20Types%20and%20Objects.pdf; 因此,type .__ new__与object .__ new__之间没有区别。 (2认同)

bob*_*nce 5

return type(name, bases, dict)
Run Code Online (Sandbox Code Playgroud)

你从中得到的是一个新的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'
Run Code Online (Sandbox Code Playgroud)

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

cls = "MyClass"
bases = ()
attributes = {'foo': 'bar'}
MyClass = MyMeta(cls, bases, attributes)
Run Code Online (Sandbox Code Playgroud)

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

Python 将__call__MyMeta's 类型中查找(type在我们的例子中)

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

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

my_meta_type = type(MyMeta)
MyClass = my_meta_type.__call__(MyMeta, cls, bases, attributes)
Run Code Online (Sandbox Code Playgroud)

在里面type.__call__()我想象是这样的:

MyClass = MyMeta.__new__(MyMeta, cls, bases, attributes)
meta_class = MyClass.__metaclass__
meta_class.__init__(MyClass, cls, bases, attributes)
return MyClass
Run Code Online (Sandbox Code Playgroud)

MyMeta.__new__()将决定如何MyClass构建:

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

type(cls, bases, attributes) 将为 MyClass