Valor de retorno de la clase Python

Resuelto Harry Hache asked hace 12 años • 6 respuestas

Estoy intentando crear una clase que devuelva un valor, no uno mismo.

Te mostraré un ejemplo comparándolo con una lista:

>>> l = list()
>>> print(l)
[]
>>> class MyClass:
>>>     pass

>>> mc = MyClass()
>>> print mc
<__main__.MyClass instance at 0x02892508>

Necesito que MyClass devuelva una lista, comolist() lo hace, no la información de la instancia. Sé que puedo hacer una subclase de lista. ¿Pero hay alguna manera de hacerlo sin subclasificar?

Quiero imitar una lista (u otros objetos):

>>> l1 = list()
>>> l2 = list()
>>> l1
[]
>>> l2
[]
>>> l1 == l2
True
>>> class MyClass():
def __repr__(self):
    return '[]'


>>> m1 = MyClass()
>>> m2 = MyClass()
>>> m1
[]
>>> m2
[]
>>> m1 == m2
False

Por que esm1 == m2 falso? Esta es la pregunta.

Lo siento si no les respondo a todos. Estoy probando todas las soluciones que me das. No puedo usarlo defporque necesito usar funciones como setitem, getitem, etc.

Harry Hache avatar Sep 14 '12 01:09 Harry Hache
Aceptado

Creo que estás muy confundido acerca de lo que está ocurriendo.

En Python todo es un objeto:

  • [](una lista) es un objeto
  • 'abcde'(una cadena) es un objeto
  • 1(un número entero) es un objeto
  • MyClass()(una instancia) es un objeto
  • MyClass(una clase) también es un objeto
  • list(un tipo, muy parecido a una clase) también es un objeto

Todos son "valores" en el sentido de que son una cosa y no un nombre que se refiere a una cosa. (Las variables son nombres que se refieren a valores). Un valor no es algo diferente de un objeto en Python.

Cuando llamas a un objeto de clase (como MyClass()o list()), devuelve una instancia de esa clase. ( listEs realmente un tipo y no una clase, pero estoy simplificando un poco aquí).

Cuando imprime un objeto (es decir, obtiene una representación de cadena de un objeto), se llama al método mágico __str__o de ese objeto y se imprime el valor devuelto.__repr__

Por ejemplo:

>>> class MyClass(object):
...     def __str__(self):
...             return "MyClass([])"
...     def __repr__(self):
...             return "I am an instance of MyClass at address "+hex(id(self))
... 
>>> m = MyClass()
>>> print m
MyClass([])
>>> m
I am an instance of MyClass at address 0x108ed5a10
>>> 

Entonces, lo que estás pidiendo, "Necesito que MyClass devuelva una lista, como list(), no la información de la instancia", no tiene ningún sentido. list()devuelve una instancia de lista. MyClass()devuelve una instancia de MyClass. Si desea una instancia de lista, simplemente obtenga una instancia de lista. Si, en cambio, el problema es cómo se ven estos objetos cuando printlos miras o los miras en la consola , entonces crea un método __str__and __repr__que los represente como quieres que se representen.

Actualización para nueva pregunta sobre igualdad

Una vez más, __str__son __repr__sólo para impresión y no afectan al objeto de ninguna otra manera. ¡El hecho de que dos objetos tengan el mismo __repr__valor no significa que sean iguales!

MyClass() != MyClass()debido a que su clase no define cómo serían iguales, vuelve al comportamiento predeterminado (del objecttipo), que es que los objetos solo son iguales a sí mismos:

>>> m = MyClass()
>>> m1 = m
>>> m2 = m
>>> m1 == m2
True
>>> m3 = MyClass()
>>> m1 == m3
False

Si desea cambiar esto, utilice uno de los métodos mágicos de comparación.

Por ejemplo, puedes tener un objeto que sea igual a todo:

>>> class MyClass(object):
...     def __eq__(self, other):
...             return True
... 
>>> m1 = MyClass()
>>> m2 = MyClass()
>>> m1 == m2
True
>>> m1 == m1
True
>>> m1 == 1
True
>>> m1 == None
True
>>> m1 == []
True

Creo que deberías hacer dos cosas:

  1. Eche un vistazo a esta guía sobre el uso de métodos mágicos en Python .
  2. Justifique por qué no está subclasificando listsi lo que quiere es muy parecido a una lista. Si la creación de subclases no es apropiada, puede delegar en una instancia de lista ajustada:

    class MyClass(object):
        def __init__(self):
            self._list = []
        def __getattr__(self, name):
            return getattr(self._list, name)
    
        # __repr__ and __str__ methods are automatically created
        # for every class, so if we want to delegate these we must
        # do so explicitly
        def __repr__(self):
            return "MyClass(%s)" % repr(self._list)
        def __str__(self):
            return "MyClass(%s)" % str(self._list)
    

    Esto ahora actuará como una lista sin ser una lista (es decir, sin subclases list).

    >>> c = MyClass()
    >>> c.append(1)
    >>> c
    MyClass([1])
    
Francis Avila avatar Sep 13 '2012 19:09 Francis Avila

Si lo que desea es una forma de convertir su clase en una especie de lista sin subclases list, simplemente cree un método que devuelva una lista:

def MyClass():
    def __init__(self):
        self.value1 = 1
        self.value2 = 2

    def get_list(self):
        return [self.value1, self.value2...]


>>>print MyClass().get_list()
[1, 2...]

Si quiso decir que print MyClass()imprimirá una lista, simplemente anule __repr__:

class MyClass():        
    def __init__(self):
        self.value1 = 1
        self.value2 = 2

    def __repr__(self):
        return repr([self.value1, self.value2])

EDITAR: Veo que quisiste decir cómo hacer que los objetos se comparen . Para eso, anula el __cmp__método.

class MyClass():
    def __cmp__(self, other):
        return cmp(self.get_list(), other.get_list())
unddoch avatar Sep 13 '2012 18:09 unddoch