__str__ vs __repr__ en Python

Aditya Raj 30 enero 2023
  1. La función str() en Python
  2. El método __str__() en Python
  3. La función repr() en Python
  4. El método __repr__() en Python
  5. __str__() vs __repr__() en Python
  6. Conclusión
__str__ vs __repr__ en Python

En Python, solemos convertir cualquier objeto en una cadena usando la función str(). De manera similar, podemos obtener la representación de cadena de un objeto usando la función repr(). Para que str() y repr() produzcan resultados, el objeto que se pasa a estas funciones debe tener una implementación del método __str__() y el método __repr__(), respectivamente.

A menudo, los desarrolladores se confunden entre las funcionalidades y los casos de uso de estos métodos. En el tutorial, vamos a discutir cómo funcionan la función str() y la función repr() y cómo el método __str__() y el método __repr__() afectan el comportamiento de un objeto.

La función str() en Python

La función str() se utiliza para obtener la representación de cadena de un objeto. Toma un objeto como argumento de entrada y devuelve su representación de cadena. Por ejemplo, podemos obtener la representación de cadena de un número de coma flotante, como se muestra en el siguiente ejemplo.

myNum = 123.456
myStr = str(myNum)
print("The number is:", myNum)
print("The string is:", myStr)

Producción :

The number is: 123.456
The string is: 123.456

De manera similar, podemos convertir otros objetos de tipos de datos incorporados, como números enteros, listas, conjuntos, tuplas, etc., en sus respectivas representaciones de cadenas utilizando la función str() como se muestra a continuación.

myNum = 123
myList = [1, 2, 3, 4, 5]
mySet = {1, 2, 3, 4, 5}
myStr1 = str(myNum)
myStr2 = str(myList)
myStr3 = str(mySet)

print("The number is:", myNum)
print("The string is:", myStr1)
print("The list is:", myList)
print("The string is:", myStr2)
print("The set is:", mySet)
print("The string is:", myStr3)

Producción :

The number is: 123
The string is: 123
The list is: [1, 2, 3, 4, 5]
The string is: [1, 2, 3, 4, 5]
The set is: {1, 2, 3, 4, 5}
The string is: {1, 2, 3, 4, 5}

Sin embargo, la salida no es comprensible cuando pasamos un objeto definido usando una definición de clase personalizada. Para observar esto, definamos una clase Student con los atributos name y age.

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age


student1 = Student("Aditya", 23)
myStr = str(student1)
print("The string representation of student object is:")
print(myStr)

Producción :

The string representation of student object is:
<__main__.Student object at 0x7f6016100070>

Aquí puede ver que la salida de la función no es tan comprensible como parecía cuando convertimos un objeto definido usando las estructuras de datos integradas. ¿Por qué pasó esto?

Cuando pasamos un objeto a la función str(), se invoca el método __str__() definido en la definición de la clase. El método __str__() devuelve la representación de cadena del objeto. La función str() luego devuelve la misma cadena. Sin embargo, no existe el método __str__() cuando definimos una clase personalizada. Debido a esto, la salida de la función str() no es muy comprensible.

El método __str__() en Python

Según nuestros requisitos, podemos implementar el método __str__() en cualquier definición de clase. La única restricción aquí es que el método debe devolver un valor de cadena. Por ejemplo, podemos implementar el método __str__() para la clase Student, como se muestra a continuación.

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        myString = "Name: {} , Age: {}".format(self.name, self.age)
        return myString

Después de implementar el método __str__(), cuando pasamos cualquier objeto Student a la función str(), devuelve la misma cadena devuelta por el método __str__(). El siguiente ejemplo muestra cómo funciona.

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        myString = "Name: {} , Age: {}".format(self.name, self.age)
        return myString


student1 = Student("Aditya", 23)
myStr = str(student1)
print("The string representation of student object is:")
print(myStr)

Producción :

The string representation of student object is:
Name: Aditya , Age: 23

Puede implementar el método __str__() de cualquier manera. Por ejemplo, podemos definir el método __str__() de la clase Student de forma alternativa como se muestra a continuación.

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        myString = "Name of student is: {} ,{} is {} years old".format(
            self.name, self.name, self.age
        )
        return myString


student1 = Student("Aditya", 23)
myStr = str(student1)
print("The string representation of student object is:")
print(myStr)

Producción :

The string representation of student object is:
Name of student is: Aditya ,Aditya is 23 years old

La forma en que implementamos el método __str__() no afecta la ejecución del programa. La salida del método __str__() se usa únicamente para mostrar la salida al usuario.

La función repr() en Python

La función repr() se utiliza para obtener la representación de cadena formal de cualquier objeto. También toma un objeto como entrada y devuelve la representación de cadena de un objeto como se muestra a continuación.

myNum = 123
myList = [1, 2, 3, 4, 5]
mySet = {1, 2, 3, 4, 5}
myStr1 = repr(myNum)
myStr2 = repr(myList)
myStr3 = repr(mySet)

print("The number is:", myNum)
print("The string is:", myStr1)
print("The list is:", myList)
print("The string is:", myStr2)
print("The set is:", mySet)
print("The string is:", myStr3)

Producción :

The number is: 123
The string is: 123
The list is: [1, 2, 3, 4, 5]
The string is: [1, 2, 3, 4, 5]
The set is: {1, 2, 3, 4, 5}
The string is: {1, 2, 3, 4, 5}

Puede observar que la salida de la función repr() es casi idéntica a la salida de la función str(). Sin embargo, el funcionamiento de ambos métodos es completamente diferente. Cuando pasamos cualquier objeto a la función str(), se invoca el método __str__(). Por otro lado, cuando pasamos cualquier objeto a la función repr(), se invoca el método __repr__(). El siguiente ejemplo muestra cómo funciona.

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        myString = "Name of student is: {} ,{} is {} years old".format(
            self.name, self.name, self.age
        )
        return myString


student1 = Student("Aditya", 23)
myStr1 = str(student1)
myStr2 = repr(student1)
print("The string representation of student object is:")
print(myStr1)
print("The output of repr() is:")
print(myStr2)

Producción :

The string representation of student object is:
Name of student is: Aditya ,Aditya is 23 years old
The output of repr() is:
<__main__.Student object at 0x7f6410b78070>

Hemos definido la clase Student con el método __str__() aquí. Puedes observar que las salidas son diferentes si pasamos una instancia de la clase Student a la función str() y la función repr().

La función str() devuelve la salida devuelta por el método __str__() mientras que la función repr() devuelve la salida devuelta por el método __repr__(). Si no implementamos el método __str__(), la función str() también devuelve la salida del método __repr__().

El método __repr__() en Python

El método __repr__() devuelve la representación canónica de un objeto en python. El método __repr__() se implementa para todos los objetos en python, independientemente de si son instancias de clases integradas o personalizadas. Puede comprender la definición del método __repr__() para objetos definidos mediante clases personalizadas de la siguiente manera.

def __repr__(self):
    return "<{0}.{1} object at {2}>".format(
        self.__module__, type(self).__name__, hex(id(self))
    )

Aquí, self.__module indica el módulo en el que se crea el objeto actual, type(self).__name__ indica el nombre de la clase y hex(id(self)) indica la identidad del objeto en formato hexadecimal. El siguiente ejemplo muestra cómo funciona.

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        myString = "Name of student is: {} ,{} is {} years old".format(
            self.name, self.name, self.age
        )
        return myString


student1 = Student("Aditya", 23)
myStr = student1.__repr__()
print("The output of __repr__() is:")
print(myStr)

Producción :

The output of __repr__() is:
<__main__.Student object at 0x7feb92cc8070>

Aquí puede ver que la salida del método __repr__() es similar al esquema definido en la definición del método. El resultado muestra que el objeto ha sido definido en el módulo __main__ y es de la clase Student. La salida también muestra la identidad del objeto.

Siempre debe evitar anular el método __repr__(). Esto se debe a que el método __repr__() se usa para crear una representación de cadena canónica del objeto, con la ayuda de la cual podemos volver a crear una instancia del mismo objeto.

Sin embargo, si anulamos el método __repr__(), no podremos crear el objeto a partir de su representación de cadena usando la función eval().
Como hemos discutido los conceptos básicos del método __str__() y el método __repr__(), enumeremos algunas de las diferencias entre los dos métodos.

__str__() vs __repr__() en Python

El método __str__() devuelve la forma de cadena legible por el usuario de un objeto que el desarrollador puede personalizar. Sin embargo, el método __repr__() devuelve una representación de cadena canónica de la cadena. En algunos casos, la cadena devuelta por el método __str__() puede ser la misma que la cadena devuelta por el método __repr__(). Puedes observar esto en el caso de los números.

Sin embargo, cuando tomamos una cadena o un objeto utilizando una definición de clase personalizada, la cadena devuelta por el método __repr__() es diferente de la cadena devuelta por el método __str__(). El siguiente ejemplo muestra cómo funciona.

myStr = "Aditya"
myStr1 = myStr.__repr__()
myStr2 = myStr.__str__()
print("The string is:", myStr)
print("The output from the __repr__() method is:", myStr1)
print("The output from the __str__() method is:", myStr2)

Producción :

The string is: Aditya
The output from the __repr__() method is: 'Aditya'
The output from the __str__() method is: Aditya

Aquí, puedes observar que la cadena devuelta por el método __str__() es Aditya. Por otro lado, el método __repr__() devuelve la representación de cadena canónica 'Aditya'.

  • Cuando pasamos la cadena devuelta por el método __repr__() a la función eval(), esta devuelve el objeto. Por otro lado, cuando pasamos la cadena devuelta por el método __str__() a la función eval(), puede devolver o no el objeto python. Por ejemplo, observe el siguiente ejemplo.
myNum = 1234
myNum1 = myNum.__repr__()
myNum2 = myNum.__str__()
print("The number is:", myNum)
print("The output from the __repr__() method is:", myNum1)
print("The output from the __str__() method is:", myNum2)
output1 = eval(myNum1)
print(output1)
output2 = eval(myNum2)
print(output2)

Producción :

The number is: 1234
The output from the __repr__() method is: 1234
The output from the __str__() method is: 1234
1234
1234

Aquí, puedes observar que podemos obtener un objeto entero a partir de una representación de cadena del entero obtenido usando el método __str__() y el método __repr__(). Ahora, mira el siguiente ejemplo.

myStr = "Aditya"
myStr1 = myStr.__repr__()
myStr2 = myStr.__str__()
print("The string is:", myStr)
print("The output from the __repr__() method is:", myStr1)
print("The output from the __str__() method is:", myStr2)
output1 = eval(myStr1)
print(output1)
output2 = eval(myStr2)
print(output2)

Producción :

The string is: Aditya
The output from the __repr__() method is: 'Aditya'
The output from the __str__() method is: Aditya
Aditya
/usr/lib/python3/dist-packages/requests/__init__.py:89: RequestsDependencyWarning: urllib3 (1.26.7) or chardet (3.0.4) doesn't match a supported version!
  warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
Traceback (most recent call last):
  File "/home/aditya1117/PycharmProjects/pythonProject/webscraping.py", line 9, in <module>
    output2 = eval(myStr2)
  File "<string>", line 1, in <module>
NameError: name 'Aditya' is not defined

Puede ver que podemos crear un objeto de cadena a partir de la cadena devuelta por el método __repr__(). Sin embargo, cuando intentamos crear el objeto de cadena utilizando la cadena devuelta por el método __str__(), el programa se encuentra con la excepción NameError.

  • Puede anular el método __str__() e implementarlo según sus necesidades. Sin embargo, no debe anular el método __repr__().
  • El método __repr__() lo utilizan principalmente los desarrolladores durante la depuración. Por otro lado, el método __str__() se utiliza para obtener una representación textual de un objeto que el usuario pueda entender.
  • El método __repr__() se invoca para producir la salida cuando escribimos el nombre de la variable o el objeto en la consola interactiva de Python. Por otro lado, el método __str__() se invoca cuando pasamos la variable a la función print() o la función str().
  • Si la definición de la clase no contiene el método __str__(), el intérprete de python invoca el método __repr__() cuando pasamos el objeto a la función str().
  • Cuando pasamos un objeto contenedor a la función print(), se imprime el método __repr__() de los elementos del objeto contenedor, independientemente de que hayamos implementado el método __str__() en la definición de la clase de los elementos o no.

Conclusión

En este artículo, hemos discutido el funcionamiento de la función str(), el método __str__(), la función repr() y el método __repr__(). También discutimos la diferencia entre los usos del método __str__() y el método __repr__().

Aunque los resultados de ambos métodos son similares, existen claras diferencias que hacen que el método __repr__() y el método __str__() sean muy diferentes entre sí. Le sugiero que use el método __repr__() para obtener la representación de cadena de los objetos en los casos en que necesite volver a crear una instancia del objeto usando la representación de cadena.

Por otro lado, debe usar el método __str__() para producir una representación legible por humanos del objeto que no tiene ningún uso en el programa aparte de informar al usuario.

Autor: Aditya Raj
Aditya Raj avatar Aditya Raj avatar

Aditya Raj is a highly skilled technical professional with a background in IT and business, holding an Integrated B.Tech (IT) and MBA (IT) from the Indian Institute of Information Technology Allahabad. With a solid foundation in data analytics, programming languages (C, Java, Python), and software environments, Aditya has excelled in various roles. He has significant experience as a Technical Content Writer for Python on multiple platforms and has interned in data analytics at Apollo Clinics. His projects demonstrate a keen interest in cutting-edge technology and problem-solving, showcasing his proficiency in areas like data mining and software development. Aditya's achievements include securing a top position in a project demonstration competition and gaining certifications in Python, SQL, and digital marketing fundamentals.

GitHub

Artículo relacionado - Python String