我试图在类构造函数(init)中返回一个值:
class A:
def __init__(self):
return 1
Run Code Online (Sandbox Code Playgroud)
但是有一个运行时错误,说init应该返回None.如果是这种情况,如何理解:
a=A()
Run Code Online (Sandbox Code Playgroud)
其中"a"被指定为类实例?
K Z*_*K Z 27
严格来说,并不是A.__new__()创建实例a.
当您定义class A(object):(或者class A:如果您使用的是Python3,class A:是旧的类已被弃用)时,它__new__来自object.__new__()被调用的继承者来创建实例a.
何时a = A()执行,会发生什么:
A() 是一个简写 A.__call__ object.__new__(cls, *args, **kwargs)在哪里cls=A,实际上是在引擎盖下创建实例a.它为新对象分配内存,然后应返回一个新对象(实例).__init__(self) 再得到与传递给它的新创建的对象叫"用来初始化"的对象.请考虑以下演示:
当我们覆盖__new__并且不再返回对象时,__init__将不会被调用:
class A(object):
def __new__(cls, *args, **kwargs):
print cls, args, kwargs
def __init__(self):
self.x = 'init!'
print self.x
In : a = A()
<class '__main__.A'> () {}
# note that "init!" has not appeared here because __new__ didn't return an
# new instance
Run Code Online (Sandbox Code Playgroud)现在,通过使用返回一个新实例object.__new__,你会看到之后__new__,__init__也将被调用:
class A(object):
def __new__(cls, *args, **kwargs):
print cls, args, kwargs
return object.__new__(cls, args, kwargs)
def __init__(self):
self.x = 'init!'
print self.x
In : a = A()
<class '__main__.A'> () {}
init!
Run Code Online (Sandbox Code Playgroud)这是另一个显示差异的演示,请注意,a可以在不调用的情况下创建实例__init__():
class A(object):
def __init__(self):
self.x = "init!"
print self.x
In : a = object.__new__(A)
In : a
Out: <__main__.A at 0x103466450>
In : a.__dict__
Out: {}
In : aa = A()
init!
In : aa
Out: <__main__.A at 0x1033ddf50>
In : aa.__dict__
Out: {'x': 'init!'}
Run Code Online (Sandbox Code Playgroud)
粗略地说,在Python中创建新对象有两种主要方法:
class语句告诉Python创建一个新的类型/类对象(通过子类化现有的类型/类,如:)object:
class Hello(object):
pass
>>> Hello.__class__
<type 'type'>
Run Code Online (Sandbox Code Playgroud)
实际上所有类/类型对象都有类型type.type
(type(type))的类型仍然是类型.
您可以子类化类型/类对象.
您还可以通过实例化现有类型对象来创建新对象.这是通过使用__call__运算符(简写())来完成的:
>>> h = hello()
>>> type(h)
<class '__main__.Hello'>
>>> type(int('1'))
<type 'int'>
Run Code Online (Sandbox Code Playgroud)
您不能子类化实例对象.
(请注意,您还可以通过其他方式创建新的实例对象,例如使用list运算符[1,2,3],在这种情况下,它会创建一个列表实例)
您可以通过type(my_obj)或检查对象的类型my_object.__class__.
实际上,这些对象也是通过实例化创建的,尽管它与前面提到的实例化略有不同.
除了class语句之外,您还可以使用
type(cls_name, parent_class_tuple, attr_dict)创建新类.例如:
type('Hello', (object,), {})
Run Code Online (Sandbox Code Playgroud)
将创建与Hello前面显示的类相同的类.
什么是type?输入元类.
type是一个元类,它是类的类,即类是元类的实例.该__class__的type仍然是type.
所以这是一个图表,显示了元类,类, 实例之间的关系:
instantiate instantiate
metaclass --------------> class ----------------> instance
type.__new__() object.__new__()
Run Code Online (Sandbox Code Playgroud)
当type调用元类来创建新类时,类似的流程如下:
type.__call__() 被罚款type.__new__()分配内存然后返回一个新的类(一个元类instace),然后调用type.__init__().type.__init__() 初始化从步骤2传递的新创建的类.您甚至可以通过子类化创建新的元类type:
class MyMeta(type):
def __new__(meta, name, bases, dct):
# do something
return super(MyMeta, meta).__new__(meta, name, bases, dct)
def __init__(cls, name, bases, dct):
# do something
super(MyMeta, cls).__init__(name, bases, dct)
Run Code Online (Sandbox Code Playgroud)
那么你可以MyMeta像这样使用这个元类创建一个新类type:
MyClass = MyMeta('MyClass', (object, ), {'x': 1})
Run Code Online (Sandbox Code Playgroud)
或者,__metaclass__在定义类时使用,它与上面显示的效果完全相同:
class MyClass(object):
__metaclass__ = MyMeta
x = 1
Run Code Online (Sandbox Code Playgroud)
它的工作原理如下:
你做:
a = A()
Run Code Online (Sandbox Code Playgroud)
A.__new__()被调用,并返回该类的实例A.
等价的:
a = A.__new__(A)
Run Code Online (Sandbox Code Playgroud)
然后Python调用
a.__init__()
Run Code Online (Sandbox Code Playgroud)
正如错误消息所述,它不应返回值.