2011-12-13 17 views
5

Sto cercando di creare una sottoclasse dell'oggetto set in Python, utilizzando il codice simile al di sotto, ma non riesco a capire una definizione sensibile di __repr__ da usare.Definizione __repr__ quando sottoclasse messo in Python

class Alpha(set): 
    def __init__(self, name, s=()): 
     super(Alpha, self).__init__(s) 
     self.name = name 

mi piacerebbe definire __repr__ in modo tale che posso ottenere il seguente risultato:

>>> Alpha('Salem', (1,2,3)) 
Alpha('Salem', set([1, 2, 3])) 

Tuttavia, se non a ignorare __repr__, l'uscita ottengo ignora il name valore ...

>>> Alpha('Salem', (1,2,3)) 
Alpha([1, 2, 3]) 

... mentre se faccio ignorare __repr__, non posso ottenere l'accesso diretto ai valori del set senza creare una nuova istanza set:

Questo funziona, ma la creazione di una nuova istanza set per __repr__ che saranno poi smaltiti sembra goffo e inefficiente per me.

C'è un modo migliore per definire __repr__ per questo tipo di classe?

Modifica: Un'altra soluzione che mi è venuta in mente: posso memorizzare il set localmente. Sembra leggermente più ordinata rispetto alle altre opzioni (creando e distruggendo qualcosa per ogni chiamata di __repr__ o usando qualche forma di manipolazione delle stringhe), ma a me sembra tutt'altro che ideale.

class Alpha(set): 
    def __init__(self, name, s=()): 
     super(Alpha, self).__init__(s) 
     self.name = name 
     self._set = set(s) 
    def __repr__(self): 
     return "%s(%r, %r)" % (self.__class__.__name__, self.name, self._set) 
+5

Il modo di chiamare 'super', ti ottenere una ricorsione infinita se le sottoclassi tentano di chiamare '__init__'. La ragione per cui 'super' prende esplicitamente una classe è che sa dove continuare nell'ordine di risoluzione dei metodi (MRO). Passa 'Alpha' (o se questo è 3.x come indicano i tag, usa semplicemente' super() '- fa la cosa giusta in qualche modo). – delnan

+0

@delnan: Dang. Grazie per quello. E pensavo di essere stato furbo nel dover evitare di specificare esplicitamente la classe. –

+0

@delnan: Per qualche ragione, Sven Marnach ha taggato questa domanda come Python 3.x. Sto effettivamente usando Python 2.6. –

risposta

7

Penso di avere qualcosa che ti fa ottenere quello che vuoi, oltre a mostrare alcuni benchmark. Sono quasi tutti equivalenti anche se sono sicuro che c'è una differenza nell'uso della memoria.

#!/usr/bin/env python 

import time 

class Alpha(set): 
    def __init__(self, name, s=()): 
      super(Alpha, self).__init__(s) 
      self.name = name 
    def __repr__(self): 
      return '%s(%r, set(%r))' % (self.__class__.__name__, 
             self.name, 
             list(self)) 

class Alpha2(set): 
    def __init__(self, name, s=()): 
      super(Alpha2, self).__init__(s) 
      self.name = name 
    def __repr__(self): 
      return '%s(%r, set(%r))' % (self.__class__.__name__, 
             self.name, 
             set(self)) 

class Alpha3(set): 
    def __init__(self, name, s=()): 
      super(Alpha3, self).__init__(s) 
      self.name = name 
    def __repr__(self): 
      rep = super(Alpha3, self).__repr__() 
      rep = rep.replace(self.__class__.__name__, 'set', 1) 
      return '%s(%r, %s)' % (self.__class__.__name__, 
            self.name, 
            rep) 

def timeit(exp, repeat=10000): 
    results = [] 
    for _ in xrange(repeat): 
     start = time.time() 
     exec(exp) 
     end = time.time()-start 
     results.append(end*1000) 
    return sum(results)/len(results) 

if __name__ == "__main__": 
    print "Alpha(): ", timeit("a = Alpha('test', (1,2,3,4,5))") 
    print "Alpha2(): ", timeit("a = Alpha2('test', (1,2,3,4,5))") 
    print "Alpha3(): ", timeit("a = Alpha3('test', (1,2,3,4,5))") 

Risultati:

Alpha(): 0,0287627220154

Alpha2(): 0,0286467552185

alpha3(): ,0285225152969

+0

Ya, opterei per 'list()' come sembra il più semplice, ma chiaramente non importa troppo. –

+1

Sono disposto a scommettere, dal punto di vista della memoria, che il primo e il secondo sono meno efficienti dal momento che stanno creando un'istanza e gettando via oggetti. Ma questo è solo un'ipotesi senza effettivamente controllare la memoria/CPU. Il terzo esempio ottiene solo una stringa e la riformatta. – jdi

+0

Forse. Credo che sia una questione di, è 'set()' o 'list()' più veloce delle 2 chiamate di 'Alpha3' (benchmark potrebbe dire di si). –

2

Non sono riuscito a trovare un modo migliore di farlo. Suppongo sia meglio che buttare via un set però.

(Python 2.x)

>>> class Alpha(set): 
...  def __init__(self, name, s=()): 
...    super(Alpha, self).__init__(s) 
...    self.name = name 
...  def __repr__(self): 
...    return 'Alpha(%r, set(%r))' % (self.name, list(self)) 
... 
>>> Alpha('test', (1, 2)) 
Alpha('test', set([1, 2])) 

O, se non ti piace il nome della classe hardcoded (anche se in realtà non dovrebbe importare).

>>> class Alpha(set): 
...  def __init__(self, name, s=()): 
...    super(Alpha, self).__init__(s) 
...    self.name = name 
...  def __repr__(self): 
...    return '%s(%r, set(%r))' % (self.__class__.__name__, self.name, list(self)) 
... 
>>> Alpha('test', (1, 2)) 
Alpha('test', set([1, 2])) 
+1

Non avrei hardcode nome di classe e userò 'self .__ class __.__ name__' invece (come me_and ha fatto) – gecco

+1

@gecco: preferenza personale. Non vedo molto il punto di non codificarlo (a meno che tu non abbia classi che lo sottoclassi), specialmente se alcuni posti lo richiedono (super-chiamata). È facile cambiare comunque. Ma ho aggiunto la versione non hardcoded e per richiesta. –

+1

Sono d'accordo con @JohnDoe. Non lo vedo come critico quando hai già bisogno di usare esplicitamente il nome della classe per le chiamate super(). Ma sì, è un po 'più dinamico. – jdi

Problemi correlati