[英]Why can't I subclass tuple in python3?
讓我們先說這個問題, 你應該使用__new__
而不是__init__
來__new__
不可變對象 。
話雖如此,讓我們看看以下代碼:
class MyTuple(tuple):
def __init__(self, *args):
super(MyTuple, self).__init__(*args)
mytuple = MyTuple([1,2,3])
這適用於python2,但在python3中,我得到:
Traceback (most recent call last):
File "tmp.py", line 5, in <module>
mytuple = MyTuple([1,2,3])
File "tmp.py", line 3, in __init__
super(MyTuple, self).__init__(*args)
TypeError: object.__init__() takes no parameters
為什么會這樣? python3有什么變化?
Python 3改變了object.__new__
和object.__init__
如何在重寫時對參數作出反應。 如果一個類重寫(或繼承覆蓋的方法) object.__init__
和object.__new__
, object.__init__
和object.__new__
如果收到任何多余的參數,將拋出異常。 在Python 2中,這將給出DeprecationWarning(默認情況下被禁止)。
tuple
沒有自己的__init__
。 它繼承了object.__init__
,所以你實際上是將一堆參數傳遞給object.__init__
那個object.__init__
沒有。 Python 2給你一個(壓制)警告,而Python 3正在使它成為一個錯誤。
代碼有一個注釋,可以很好地解釋object.__init__
和object.__new__
對額外參數的微妙處理:
/* You may wonder why object.__new__() only complains about arguments
when object.__init__() is not overridden, and vice versa.
Consider the use cases:
1. When neither is overridden, we want to hear complaints about
excess (i.e., any) arguments, since their presence could
indicate there's a bug.
2. When defining an Immutable type, we are likely to override only
__new__(), since __init__() is called too late to initialize an
Immutable object. Since __new__() defines the signature for the
type, it would be a pain to have to override __init__() just to
stop it from complaining about excess arguments.
3. When defining a Mutable type, we are likely to override only
__init__(). So here the converse reasoning applies: we don't
want to have to override __new__() just to stop it from
complaining.
4. When __init__() is overridden, and the subclass __init__() calls
object.__init__(), the latter should complain about excess
arguments; ditto for __new__().
Use cases 2 and 3 make it unattractive to unconditionally check for
excess arguments. The best solution that addresses all four use
cases is as follows: __init__() complains about excess arguments
unless __new__() is overridden and __init__() is not overridden
(IOW, if __init__() is overridden or __new__() is not overridden);
symmetrically, __new__() complains about excess arguments unless
__init__() is overridden and __new__() is not overridden
(IOW, if __new__() is overridden or __init__() is not overridden).
However, for backwards compatibility, this breaks too much code.
Therefore, in 2.6, we'll *warn* about excess arguments when both
methods are overridden; for all other cases we'll use the above
rules.
*/
我一直在挖掘C代碼庫,我還沒有找到任何關於在python3中禁止這種行為的改變的真正線索。 我已經在python2.7,python3.3,python3.5和python3.6上測試過了。 你的代碼唯一沒有異常的工作是在python2.7上。 我還沒有在文檔中找到任何關於為什么會改變的引用,但我確實有一些想法......
首先,我們同意tuple.__init__
不能做任何事情,因為tuple
是不可變的。 到__init__
被調用時,元組已經被凍結。 因此,這引出了我的猜測 - 因為tuple.__init__
什么都不做,開發人員認為它誤導了它允許它接受任何參數。 通過阻止基類接受參數,它們鼓勵人們覆蓋__new__
(因此,鼓勵對不可變對象進行適當的繼承)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.