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

时间:2012-10-24 05:11:16

标签: python

我尝试在类构造函数( init )中返回一个值:

class A:
  def __init__(self):
    return 1

但是有一个运行时错误,说 init 应该返回None。如果是这种情况,如何理解:

a=A()

其中" a"被指定为类实例?

4 个答案:

答案 0 :(得分:27)

严格地说,创建实例A.__new__()不是a

如果您定义class A(object):(或class A:,如果您使用的是Python3,class A:old-style class that has been deprecated),则继承__new__正在调用object.__new__()来创建实例a

执行a = A()时,会发生什么:

  1. A()A.__call__
  2. 的简写
  3. object.__new__(cls, *args, **kwargs)其中cls=A是在引擎盖下实际创建实例a的内容。它为新对象分配内存,应该然后返回一个新对象(实例)。
  4. 当且仅当返回新创建的对象时__init__(self) 然后调用新传入的对象传递给它“initilize”对象
  5. 考虑以下演示:

    • 当我们覆盖__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
      
    • 现在,使用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!
      

    以下是显示差异的另一个演示,请注意,可以在不调用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!'}
    

    现在为了好奇(并且还要刷新我自己的记忆=]):

    粗略地说,在Python中创建新对象有两种主要方法:

    通过子类化创建新对象( type / class ):

    class语句告诉Python创建一个新的类型 / 对象(通过 子类化现有的类型 / ,例如object):

    class Hello(object):
        pass
    >>> Hello.__class__
    <type 'type'>
    

    实际上,所有 / 类型对象都具有类型typetype的类型 (type(type))仍然是类型。

    您可以继承类型 / 对象。

    通过实例化:

    创建新对象(实例

    您还可以通过实例化现有的类型对象来创建新对象。 这是通过使用__call__运算符(()的简写)来完成的:

    >>> h = hello()
    >>> type(h)
    <class '__main__.Hello'>
    >>> type(int('1'))
    <type 'int'>
    

    您不能对实例对象进行子类化。

    (请注意,您还可以通过其他方式创建新的实例对象 使用列表运算符[1,2,3],在这种情况下,它创建一个列表实例)

    您可以按type(my_obj)my_object.__class__检查对象的类型。


    现在您知道如何创建实例对象,但真正创建类型 / 对象(允许创建实例对象) )?

    实际上,这些对象也是通过实例化创建的,尽管它是一个 与前面提到的实例略有不同。

    除了class声明之外,您还可以使用 type(cls_name, parent_class_tuple, attr_dict)创建一个新类。 例如:

    type('Hello', (object,), {})
    

    将创建与前面显示的类相同的Hello类。

    什么是type?输入元类

    type元类,它是的类,即类是 元类的实例。 __class__的{​​{1}}仍为type

    所以这是一个显示元类之间关系的图表, 实例

    type

    当调用元类 instantiate instantiate metaclass --------------> class ----------------> instance type.__new__() object.__new__() 来创建新类时,类似的流程如下:

    1. type已被罚款
    2. type.__call__()分配内存,然后返回一个新类(元类实例),然后调用type.__new__()
    3. type.__init__()初始化从步骤2传递的新创建的类。
    4. 您甚至可以通过继承type.__init__()

      来创建新的元类
      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) 元类创建一个新类 与MyMeta

      type

      或者,在定义您的类时使用MyClass = MyMeta('MyClass', (object, ), {'x': 1}) ,它具有完全相同的类 与上面显示的效果相同:

      __metaclass__

答案 1 :(得分:8)

它的工作原理如下:

你这样做:

a = A()
调用

A.__new__(),并返回类A的实例。

等效地:

a = A.__new__(A)
然后Python调用

a.__init__()

正如错误消息所示,不应返回值。

答案 2 :(得分:4)

如您所知,Python中的所有内容都是对象,类也不例外。类A是一个方法__call__(...)的对象,它允许您编写a = A()之类的内容。在引擎盖下,A.__call__将首先使用静态方法__new__(具有合理的默认实现)创建对象,然后使用适当的构造函数args调用新对象的__init__

答案 3 :(得分:2)

__init__应返回None的要求是一个有意义的实现选择,它允许您依赖类型类的对象一致地返回一个对象的事实 类的实例类型。在许多其他语言中也是如此,例如C ++。

如果实施方式不同,会造成无用的混淆。