【问题标题】:object takes no parameters after defining __new__对象在定义 __new__ 后不带参数
【发布时间】:2019-02-04 07:24:24
【问题描述】:

在 python 3.3 及更高版本中,当我们覆盖 __new__() 时,我们不必将参数和关键字参数传递给 super().__new__()object.__new__()。但是这个对super().__new__() 的调用会返回一个类的实例。

那么python如何将其余的参数传递给__init__呢?

class Spam(object):
    ''' Hello I am Spam '''

    def __new__(cls, *args, **kwargs):
        print("Creating Instance")
        instance = object.__new__(cls) # Who passed *args and **kwargs to __init__?
        print(instance)
        return instance

    def __init__(self, a, b):
        print("Init Called")
        self.a = a
        self.b = b

有人可以解释一下这里发生了什么吗?

【问题讨论】:

标签: python python-3.x python-internals


【解决方案1】:

您将 cls 作为参数传递给 object.__new__,因此解释器可以检查 instance 是否是 cls 的实例.

初始化器 (__init__) 由分配器 (__new__) 自动调用,[Python.Docs]: object.__new__(cls[, ...]) 状态(重点是我的):

如果__new__()返回一个cls的实例,那么新实例的__init__()方法将像__init__(self[, ...])一样被调用,其中self em> 是新实例,其余参数与传递给 __new__() 的参数相同。

如果 __new__() 没有返回 cls 的实例,那么新实例的 __init__() 方法将不会被调用。

code00.py

#!/usr/bin/env python3

import sys


class Spam(object):
    ''' Hello I am Spam '''

    def __new__(cls, *args, **kwargs):
        print("Creating Instance")
        instance = object.__new__(cls) # Who passed *args and **kwargs to __init__?
        print(instance)
        #return instance  # If you return anything else (1, object(), or None by commenting the line) here, __init__ won't be called
        if len(sys.argv) == 1:  # DO NOT DO THIS!!! It's just for demo purposes
            return instance


    def __init__(self, a, b):
        print("Init Called")
        self.a = a
        self.b = b


def main():
    spam = Spam(1, 2)
    print(type(spam), dir(spam))


if __name__ == "__main__":
    print("Python {0:s} on {0:s}\n".format(sys.version, sys.platform))
    main()

输出

e:\Work\Dev\StackOverflow\q054511671>"e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code00.py
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32

Creating Instance
<__main__.Spam object at 0x000001F8E24D14E0>
Init Called
<class '__main__.Spam'> ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b']

e:\Work\Dev\StackOverflow\q054511671>"e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code.py arg
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32

Creating Instance
<__main__.Spam object at 0x0000020808F71550>
<class 'NoneType'> ['__bool__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

请注意,这不是特定于 Python 3(检查 [Python 2.Docs]: Data model),而是特定于 [Python]: New-style Classes 有关更多详细信息,您还可以检查[Python 2.2.Docs]: Overriding the __new__ methodSingleton 类)。

【讨论】:

  • 这很有帮助,感谢您的回复。虽然我不确定这种行为背后的意图是什么。
  • 什么意思?这有点明显。语法更清晰(对用户来说更简单)。请注意,同样的事情也适用于 Python 2.7.15
【解决方案2】:

这里重要的是最初的电话,比如spam = Spam('x', 1)

在内部,Python 调用__new__ 作为类Spam 上的类方法使用传递的参数Spam.__new__ 实际上做了什么并不重要,它只是应该返回一个对象。

它确实使用object.__new__ 来构建Spam 对象。由于创建的对象具有正确的类,Python 使用初始参数对其调用__init__

【讨论】:

  • 谢谢谢尔盖。 @ChristiFati 提到的这一点确实值得理解。我不确定那个“返回实例”语句是如何产生影响的。即使它有所作为,这背后的意图也可能是什么。
猜你喜欢
  • 1970-01-01
  • 2016-04-03
  • 1970-01-01
  • 2013-06-09
  • 1970-01-01
  • 2013-03-12
  • 2011-07-06
  • 2015-01-15
  • 1970-01-01
相关资源
最近更新 更多