8

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

class A:
  def __init__(self):
    return 1

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

a=A()

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

4

4 回答 4

28

严格来说,这并不是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
    
  • 现在,通过 using 返回一个新实例,object.__new__您将看到 after也会被调用:__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__是。typetype

所以这里有一张图,显示了metaclassclassinstance之间的关系:

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

type调用元类来创建一个新类时,类似的流程是:

  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
于 2012-10-24T05:30:40.607 回答
8

它是这样工作的:

你做:

a = A()

A.__new__()被调用,并返回类的一个实例A

等效地:

a = A.__new__(A)

然后 Python 调用

a.__init__()

正如错误消息所说,它不应该返回一个值。

于 2012-10-24T05:15:37.667 回答
4

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

于 2012-10-24T05:19:56.030 回答
2

__init__应该返回的要求None是一个有意识的实现选择,它让您依赖于类类型的对象始终返回类实例类型的对象这一事实。在许多其他语言(例如 C++)中也是如此。

如果以不同的方式实施,它将造成无用的混乱。

于 2012-10-24T05:27:09.053 回答