Domanda Sottoclasse la tupla di Python con più argomenti __init__


Il seguente codice funziona:

class Foo(tuple):

    def __init__(self, b):
        super(Foo, self).__init__(tuple(b))

if __name__ == '__main__':
    print Foo([3, 4])

$ python play.py 
play.py:4: DeprecationWarning: object.__init__() takes no parameters
  super(Foo, self).__init__(tuple(b))
(3, 4)

Ma non il seguente:

class Foo(tuple):

    def __init__(self, a, b):
        super(Foo, self).__init__(tuple(b))

if __name__ == '__main__':
    print Foo(None, [3, 4])

$ python play.py 
Traceback (most recent call last):
  File "play.py", line 7, in <module>
    print Foo(None, [3, 4])
TypeError: tuple() takes at most 1 argument (2 given)

Perché?


44
2017-10-14 10:10


origine


risposte:


Perché le tuple sono immutabili, devi scavalcare __new__ anziché:

documenti python

object.__new__(cls[, ...])

Chiamato per creare una nuova istanza di   classe cls. __new__() è una statica   metodo (con custodia speciale, quindi non è necessario   dichiararlo come tale) che prende il   classe di cui era un'istanza   richiesto come primo argomento. Il   gli argomenti rimanenti sono quelli passati   all'espressione del costruttore di oggetti   (la chiamata alla classe). Il ritorno   valore di __new__() dovrebbe essere il nuovo   istanza di oggetto (di solito un'istanza   di cls).

Le implementazioni tipiche creano un nuovo   istanza della classe invocando il   superclasse di __new__() metodo usando    super(currentclass, cls).__new__(cls[, ...]) con argomenti appropriati e   quindi modificando il nuovo creato   istanza necessaria prima di tornare   esso.

Se __new__() restituisce un'istanza di    cls, quindi la nuova istanza    __init__() il metodo sarà invocato come __init__(self[, ...]), dove self è la nuova istanza e il rimanente   gli argomenti sono gli stessi che sono stati passati   a __new__().

Se __new__() non restituisce un   istanza di cls, quindi il nuovo   esempio di __init__() il metodo non lo farà   essere invocato.

__new__() è inteso principalmente per consentire sottoclassi di tipi immutabili (come    int, str, o tuple) personalizzare   creazione di istanze. È anche comunemente   sovrascritto in metaclassi personalizzati in   per personalizzare la creazione della classe.


58
2017-10-14 10:24



Per assegnare il valore della tupla è necessario sovrascrivere il __new__ metodo:

class Foo(tuple):

    def __new__ (cls, a, b):
        return super(Foo, cls).__new__(cls, tuple(b))

Gli argomenti sembrano essere ignorati dal __init__ implementazione della classe tuple, ma se hai bisogno di fare alcune cose di init puoi farlo come segue:

class Foo(tuple):

    def __new__ (cls, a, b):
        return super(Foo, cls).__new__(cls, tuple(b))

    def __init__(self, a, b):
        self.a=a
        self.b=b

if __name__ == '__main__':
    foo = Foo(None, [3, 4])
    print foo
    print foo.a
    print foo.b

41
2017-10-26 21:38