python类__init__方法会隐式返回None吗?

Hai*_*ang 7 python

我试图在类构造函数(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()执行,会发生什么:

  1. A() 是一个简写 A.__call__
  2. object.__new__(cls, *args, **kwargs)在哪里cls=A,实际上是在引擎盖下创建实例a.它为新对象分配内存,然后返回一个新对象(实例).
  3. 当且仅当返回新创建的对象不会__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调用元类来创建新类时,类似的流程如下:

  1. type.__call__() 被罚款
  2. type.__new__()分配内存然后返回一个新的类(一个元类instace),然后调用type.__init__().
  3. 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)


Joe*_*ett 8

它的工作原理如下:

你做:

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)

正如错误消息所述,它不应​​返回值.

  • 我认为它将`object .__ new __(A)`或`A .__ new __(A)`与`A`作为参数调用,因为`A .__ new __()`没有参数引发*TypeError*说*object .__ new __() :没有足够的论据* (2认同)