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

发布于 2021-01-29 15:17:04

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

class A:
  def __init__(self):
    return 1

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

a=A()

其中“ a”被分配为类实例?

关注者
0
被浏览
244
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    严格来说,不是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()
      () {}

      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()
      () {}
      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'>
    

    实际上,所有 / 类型 对象都具有类型typetypetype(type))的类型仍为type。

    您可以将 类型 / 对象作为子

    通过实例化创建新对象( 实例 ):

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

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

    您不能子类化实例对象。

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

    您可以通过type(my_obj)或检查对象的类型my_object.__class__


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

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

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

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

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

    什么type啊 输入 metaclass

    type是一个 metaclass ,它是class的
    ,即,class是metaclasses的实例。该__class__type仍然是type

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

                instantiate             instantiate
    metaclass   --------------> class   ---------------->    instance
                type.__new__()          object.__new__()
    

    type调用metaclass创建新类时,类似的流程如下:

    1. type.__call__() 被谴责
    2. type.__new__()分配内存,然后返回一个新的类(一个元类实例),然后调用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)
    

    那么您可以MyMeta像使用type以下方法一样,从此元类创建一个新类:

    MyClass = MyMeta('MyClass', (object, ), {'x': 1})
    

    或者,__metaclass__在定义类时使用,其效果与上面显示的效果完全相同:

    class MyClass(object):
        __metaclass__ = MyMeta
        x = 1
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看