【问题标题】:What is the downside of using object.__new__ in __new__?在 __new__ 中使用 object.__new__ 有什么缺点?
【发布时间】:2016-09-15 15:54:20
【问题描述】:

编码异常类,我遇到了这个错误:

TypeError: object.__new__(A) is not safe, use Exception.__new__()

这里发布了一个类似的问题: TypeError: object.__new__(int) is not safe, use int.__new__()。所以__new__ 被弃用的原因如下:

[Python-Dev] __new__ deprecation

吉多·范罗森

“消息的意思就是它所说的。:-) 打电话是没有意义的 object.__new__() 具有多个类参数,以及任何代码 这样做只是将这些 args 倾倒到一个黑洞中。”

但是 3.3 中我得到“不安全”的警告是可怕的。我试图理解使用object.__new__ 的含义,让我们考虑这个例子:

>>> class A(Exception):
...     def __new__(cls, *args):
...             return object.__new__(A)
...
>>> A()
TypeError: object.__new__(A) is not safe, use Exception.__new__()

惨败。另一个例子:

>>> class A(object):
...     def __new__(cls, *args):
...             return object.__new__(A)
...
>>>
>>> A()
<__main__.A object at 0x0000000002F2E278>

工作正常。尽管object 是一个内置类,就像Exception 就它们的角色而言,它们具有内置类的特征。现在有了Exception,第一个例子提出了TypeError,但是有了object,它没有吗?

(a) 使用object.__new__ 导致 Python 在第一个示例中引发错误 (TypeError:...is not safe...) 的缺点是什么?

(b) 在调用__new__ 之前,Python 会执行什么样的检查?或者:第一个例子中 Python 报错的条件是什么?

【问题讨论】:

    标签: python


    【解决方案1】:

    调用object.__new__没有问题,但是不调用Exception.__new__有问题。

    Exception 类的设计方式是,必须调用其__new__,因此如果不调用它会报错。

    有一个问题,为什么这只发生在内置类中。事实上,Python 对每一个被编程为这样做的类都做到了。

    以下是自定义类中相同机制的简化穷人实现:

    class A(object):
        def __new__(cls):
            rtn = object.__new__(cls)
            rtn.new_called = True
            return rtn
    
        def __init__(self):
            assert getattr(self,'new_called',False), \
                "object.__new__ is unsafe, use A.__new__"
    
    class B(A):
        def __new__(cls):
            return object.__new__(cls)
    

    现在:

    >>> A()
    <__main__.A object at 0x00000000025CFF98>
    
    >>> B()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 7, in __init__
    AssertionError: object.__new__ is unsafe, use A.__new__
    

    附带说明,问题中的这个示例实际上有两个错误:

    >>> class A(Exception):
    ...     def __new__(cls, *args):
    ...             return object.__new__(A)
    

    首先是__new__object上被调用,从而忽略Exception.__new__

    另一个同样严重的是A被传递给__new__而不是cls,这阻碍了从A继承的所有类。

    看这个例子:

    class A(object):
        def __new__(cls):
            return object.__new__(A)  # The same erroneous line, without Exception
    
    class B(A):
        pass
    

    现在B() 不会创建B 的实例:

    >>> B()
    <__main__.A object at 0x00000000025D30B8>
    

    【讨论】:

    • 我刚刚意识到该机制是在object.__new__ 中编码的。看this code。也就是说,object.__new__ 引发了TypeError。现在说“不安全”是很合理的。尽管在子类中覆盖Exception.__new__ 不会引发错误,即使Exception.__new__ 没有在Subclass.__new__ 内部被调用,这也是同样危险的。
    【解决方案2】:

    调用object.__new__(A) 会返回A 的实例,但如果已定义,则不会调用Exception.__new__()

    【讨论】:

    • "但是如果它已定义,则无需调用Exception.__new__() 这不会成为问题,因为我们将__new__ 定义得更低(在子类中)。这与是否调用Exception.__new__无关。如果我们有两个超类,每个超类都有__new__方法:C(A,B),那么最左边的__new__将被调用,即A.__new__和@ 987654332@不会被调用。你能举个例子吗?
    • 您提出的是一个单独的问题,可以通过显式调用A.__new__()B.__new__() 或使用super 并确保所有祖先类也使用它来解决。未能调用Exception.__new__ 是一个大问题,如果您错过了Exception 特定的配置并计划将您的对象传递给期望正确配置的Exception 实例的人。
    • 我明白你的意思:(用另一个 __new__ 替换 __new__ 可能会跳过创建期间对象所需的部分或全部关键配置)。
    • 如果您考虑this code,您会注意到Python 仅针对内置类引发(TypeError:... is not safe...)。从the code 可以看出,A 类有自己的__new__,而B 类直接继承自A,并在其__new__ 中使用object.__new__(*b)。在 Python 3.3 中运行时,这不会引发任何错误。为什么 Python 只为内置类引发异常,而不是用户定义的类?
    猜你喜欢
    • 2012-10-08
    • 1970-01-01
    • 1970-01-01
    • 2013-10-16
    • 1970-01-01
    • 2014-03-01
    • 1970-01-01
    • 2021-06-03
    • 1970-01-01
    相关资源
    最近更新 更多