簡體   English   中英

為什么我不能在python3中子類化元組?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM