2011-12-13 11 views
5

Estoy tratando de subclasificar el objeto set en Python, usando un código similar al siguiente, pero no puedo encontrar una definición sensata de __repr__ para usar.Definiendo __repr__ cuando se establece una subclasificación en Python

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

me gustaría definir __repr__ de tal manera que pueda obtener el siguiente resultado:

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

Sin embargo, si no anulan __repr__, la salida consigo ignora la name valor ...

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

... mientras que si lo hago anular __repr__, no puedo obtener acceso directo a los valores en el conjunto sin necesidad de crear una nueva instancia conjunto:

Esto funciona, pero la creación de una nueva instancia conjunto de __repr__ que luego serán eliminados parece torpe e ineficiente para mí.

¿Existe alguna manera mejor de definir __repr__ para este tipo de clase?

Editar: Otra solución que se me ocurrió: puedo almacenar el juego localmente. Parece algo más ordenado que las otras opciones (crear y destruir algo para cada llamada de __repr__ o usar alguna forma de manipulación de cadenas), pero aún así parece menos que ideal para mí.

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

La forma de llamar 'super', podrás obtener recursión infinita si las subclases intentan llamar a '__init__'. La razón por la que 'super' explícitamente toma una clase es que sabe dónde continuar en el orden de resolución de método (MRO). Pase 'Alfa' (o si esto es 3.x como indican las etiquetas, simplemente use' super() '- de algún modo hace lo correcto). – delnan

+0

@delnan: Dang. Gracias por eso. Y estaba yo pensando que estaba siendo astuto al evitar especificar la clase explícitamente. –

+0

@delnan: por alguna razón, Sven Marnach etiquetó briely esta pregunta como Python 3.x. En realidad estoy usando Python 2.6. –

Respuesta

7

creo que tengo algo que le consigue lo que quiere, además de mostrar algunos puntos de referencia. Casi todos son equivalentes, aunque estoy seguro de que hay una diferencia en el uso de la 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))") 

Resultados:

Alpha(): 0.0287627220154

alfa2(): 0.0286467552185

Alpha3(): 0.0285225152969

+0

Ya, yo optaría por 'list()' ya que parece ser el más sencillo, pero claramente no importa demasiado. –

+1

Estoy dispuesto a apostar, en cuanto a la memoria, que el primero y el segundo son menos eficientes ya que están creando instancias y arrojando objetos. Pero eso es solo una suposición sin verificar realmente la memoria/CPU. El tercer ejemplo solo obtiene una cadena y la reformatea. – jdi

+0

Posiblemente. Supongo que se trata de que 'set()' o 'list()' sea más rápido que las 2 llamadas de 'Alpha3' (el índice de referencia puede ser sí). –

2

No pude encontrar ninguna otra manera mejor que hacer esto. Supongo que es mejor que tirar un juego sin embargo.

(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, si no le gusta el nombre de clase codificado (aunque en realidad no debería importar).

>>> 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

No codificaría classname y usar 'self .__ class __.__ name__' en su lugar (como me_y lo hice) – gecco

+1

@gecco: preferencia personal. No veo mucho sentido en no codificarlo en forma rígida (a menos que vayas a tener clases que lo subclasifiquen), especialmente porque algunos lugares aún lo requieren (super llamada). Es fácil de cambiar de todos modos. Pero he agregado la versión no codificada y también por solicitud. –

+1

Estoy de acuerdo con @JohnDoe. No lo veo como algo crítico cuando ya necesita usar explícitamente el nombre de clase para las llamadas a super(). Pero sí, es un poco más dinámico. – jdi

Cuestiones relacionadas