Si alguien escribe una clase en python y no puede especificar su propio __repr__() , se le proporciona uno predeterminado. Sin embargo, supongamos que queremos escribir una función que tenga el mismo comportamiento, o similar, al __repr__() predeterminado. Sin embargo, queremos que esta función tenga el comportamiento del método __repr__() predeterminado incluso si el __repr__() real para la clase estaba sobrecargado. Es decir, supongamos que queremos escribir una función que tenga el mismo comportamiento que un __repr__() predeterminado, independientemente de si alguien sobrecargó el __repr__() o no. ¿Cómo podríamos hacerlo?
class DemoClass: def __init__(self): self.var = 4 def __repr__(self): return str(self.var) def true_repr(x): # [magic happens here] s = "I'm not implemented yet" return s obj = DemoClass() print(obj.__repr__()) print(true_repr(obj)) print(obj.__repr__()) imprime 4 , pero print(true_repr(obj)) imprime algo como:
<__main__.DemoClass object at 0x0000000009F26588>
Puede usar object.__repr__(obj) . Esto funciona porque el comportamiento predeterminado de repr está definido en object.__repr__ .
Tenga en cuenta que la mejor respuesta es probablemente usar object.__repr__ directamente, como han señalado los demás. Pero uno podría implementar esa misma funcionalidad más o menos como:
>>> def true_repr(x): ... type_ = type(x) ... module = type_.__module__ ... qualname = type_.__qualname__ ... return f"<{module}.{qualname} object at {hex(id(x))}>" ...Asi que....
>>> A() hahahahaha >>> true_repr(A()) '<__main__.A object at 0x106549208>' >>>Por lo general, podemos usar object.__repr__ para eso, pero esto será "objeto repr para cada elemento, por lo que:
>>> object.__repr__(4) '<int object at 0xa6dd20>' Dado que un int es un object , pero con __repr__ .
Si desea subir un nivel de sobrescritura, podemos usar super(..) :
>>> super(type(4), 4).__repr__() # going up one level '<int object at 0xa6dd20>' Para un int , eso nuevamente significa que imprimiremos <int object at ...> , pero si, por ejemplo, hiciéramos una subclase de int , entonces usaría __repr__ de int nuevamente, como:
class special_int(int): def __repr__(self): return 'Special int'Entonces se verá como:
>>> s = special_int(4) >>> super(type(s), s).__repr__() '4' Lo que hacemos aquí es crear un objeto proxy con super(..) . Super recorrerá el orden de resolución del método (MRO) del objeto e intentará encontrar la primera función (de una superclase de s ) que haya anulado la función. Si usamos herencia simple, ese es el padre más cercano que anula la función, pero si hay alguna herencia múltiple involucrada, entonces esto es más complicado. Por lo tanto, seleccionamos el __repr__ de ese padre y llamamos a esa función.
Esta es también una aplicación bastante extraña de super ya que por lo general la clase (aquí type(s) ) es fija, y no depende del tipo de s en sí mismo, ya que de lo contrario múltiples llamadas super(..) darían como resultado una Bucle infinito.
Pero por lo general es una mala idea interrumpir la anulación de todos modos. La razón por la que un programador anula una función es para cambiar el comportamiento . Por supuesto, no respetar esto a veces puede resultar en algunas funciones útiles, pero con frecuencia resultará en el hecho de que los contratos de código ya no se cumplen. Por ejemplo, si un programador anula __eq__ , también anulará __hash__ , si usa el hash de otra clase y el __eq__ real, entonces las cosas comenzarán a fallar.
Llamar directamente a la función mágica también se ve con frecuencia como un antipatrón , por lo que es mejor que también lo evites.