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__
>>>
【讨论】:
对于 python3class 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__()
主要是为了允许不可变 类型的子类(如int
、str
或tuple
)自定义实例创建。也是 通常在自定义元类中被覆盖以自定义类 创作。
所以在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 对象创建过程中元类, __new__, __call__, __init__ 的处理