Clases en Python: lo est´as haciendo mal
V´ıctor Terr´on — http://github.com/vterron
Introducci´on
Programaci´on orientada a objetos
Una cita ap´ocrifa
“Object-oriented programming is an exceptionally bad idea which
could only have originated in California” [Edsger W. Dijkstra]
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
2 / 230
Introducci´on
Programaci´on orientada a objetos
Lo que en realidad dijo
“For those who have wondered: I don’t think object-oriented
programming is a structuring paradigm that meets my standards of
elegance.” [Edsger W. Dijkstra, 1999] [Fuente]
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
3 / 230
Introducci´on
Programando clases en Python
El objetivo de esta charla es ayudarnos a
hacer idiom´aticas y elegantes nuestras
clases en Python.
En mayor o menor medida todo el mundo usa progra-
maci´on orientada a objetos, pero hay una serie de aspec-
tos fundamentales que es indispensable conocer para evitar
que nuestro c´odigo sea innecesariamente feo o complejo.
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
4 / 230
Introducci´on
Nuestra reacci´on a veces
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
5 / 230
Introducci´on
Programando clases en Python
La premisa es que somos m´ınimamente familiares con los conceptos
b´asicos de programaci´on orientada a objetos, y que hemos trabajado
un poco con nuestras propias clases en Python.
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
6 / 230
Introducci´on
Un muy brev´ısimo repaso
Llamamos clase a la representaci´on abstracta de un concepto. Por
ejemplo, ’perro’, ’n´umero entero’ o ’servidor web’.
Uno
Las clases se componen de atributos y m´etodos.
Dos
Un objeto es cada una de las instancias de una clase.
Tres
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
7 / 230
Introducci´on
Ejemplo: clase Perro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#! /usr/bin/env python
# encoding: UTF-8
class Perro(object):
def __init__(self, nombre, raza, edad):
self.nombre = nombre
self.raza = raza
self.edad = edad
def ladra(self):
print self.nombre, "dice ’¡Wooof!’"
mascota = Perro("Lassie", "Collie", 18)
mascota.ladra()
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
8 / 230
Introducci´on
¡No os limit´eis a escuchar!
No suele ser divertido escuchar a nadie hablar durante
casi una hora. Participad, intervenid, criticad, opinad.
¡Si digo algo que no tiene ning´un sentido, corregidme!
Transparencias y c´odigo fuente en:
http://github.com/vterron/PyConES-2014
Erratas, correcciones, enlaces, ¡cualquier cosa!
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
9 / 230
´Indice
Introducci´on
Introducci´on
1
2 00. Heredando de object (new-style)
3 01. super()
4 02. El primer par´ametro: self
5 03. Variables de clase (est´aticas)
6 04. Atributos privados y ocultos
7 05. M´etodos est´aticos y de clase
8 06. Propiedades (@property)
9 07.
10 08. collections.namedtuple()
11 09.
12 Ep´ılogo
init () y
new ()
str () y
repr ()
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
10 / 230
00. Heredando de object (new-style)
´Indice
Introducci´on
1
2 00. Heredando de object (new-style)
3 01. super()
4 02. El primer par´ametro: self
5 03. Variables de clase (est´aticas)
6 04. Atributos privados y ocultos
7 05. M´etodos est´aticos y de clase
8 06. Propiedades (@property)
9 07.
10 08. collections.namedtuple()
11 09.
12 Ep´ılogo
init () y
new ()
str () y
repr ()
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
11 / 230
00. Heredando de object (new-style)
00. Heredando de object (new-style)
Hemos de heredar de object para que nuestra clase sea new-style.
1
2
3
4
5
6
7
8
9
10
class Perro(object):
def __init__(self, nombre, raza, edad):
self.nombre = nombre
self.raza = raza
self.edad = edad
mascota = Perro("Lassie", "Collie", 18)
print "Clase:", mascota.__class__
print "Tipo:", type(mascota)
Clase: <class ’__main__.Perro’>
Tipo: <class ’__main__.Perro’>
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
12 / 230
00. Heredando de object (new-style)
00. Heredando de object: por qu´e
Algo de historia
Las clases new-style aparecieron en Python 2.2
(diciembre de 2001)
Hasta Python 2.1, el concepto de clase no ten´ıa relaci´on
con el tipo:
los objetos de todas las (old-style) clases
ten´ıan el mismo tipo: <type ’instance’ >. Las clases
new-style unifican clase y tipo — dicho de otra forma: una
clase new-style no es sino un tipo definido por el usuario.
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
13 / 230
00. Heredando de object (new-style)
00. Heredando de object: ejemplo
1 class Perro: # no heredamos de ’object’
2
3
4
5
6
def __init__(self, nombre, raza, edad):
self.nombre = nombre
self.raza = raza
self.edad = edad
7
8 sargento = Perro("Stubby", "Bull Terrier", 9)
9 print "Clase:", sargento.__class__
10 print "Tipo:", type(sargento)
Clase: __main__.Perro
Tipo: <type ’instance’>
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
14 / 230
00. Heredando de object (new-style)
00. La vida antes de Python 2.2
Pero no es una cuesti´on s´olo de qu´e devuelve type()
No exist´ıa super()...
... ni los descriptores...
... ni
slots
El MRO (Method Resolution Order ) era mucho m´as simple.
Las clases pod´ıan ser lanzadas, sin heredar de Exception.
Old style and new style classes in Python
https://stackoverflow.com/a/19950198/184363
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
15 / 230
00. Heredando de object (new-style)
00. Lanzando una clase new-style
1 class Spam(object):
pass
2
3
4 raise Spam()
Traceback (most recent call last):
File "./code/00/02-new-style-raise.py", line 4, in <module>
raise Spam()
TypeError: exceptions must be old-style classes or derived from
BaseException, not Spam
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
16 / 230
00. Heredando de object (new-style)
00. Lanzando una clase old-style
1 class Foo:
pass
2
3
4 raise Foo()
Traceback (most recent call last):
File "./code/00/03-old-style-raise.py", line 4, in <module>
raise Foo()
__main__.Foo: <__main__.Foo instance at 0x402b948c>
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
17 / 230
00. Heredando de object (new-style)
00. Heredando de object (new-style)
Por compatibilidad, las clases siguen siendo old-style
por defecto.
En Python 3 las clases old-style han desaparecido
— heredar de object es opcional.
El resumen es que tenemos que heredar siempre de
object (o de otra clase new-style, claro).
Moraleja
Hay que heredar de object siempre
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
18 / 230
´Indice
01. super()
Introducci´on
1
2 00. Heredando de object (new-style)
3 01. super()
4 02. El primer par´ametro: self
5 03. Variables de clase (est´aticas)
6 04. Atributos privados y ocultos
7 05. M´etodos est´aticos y de clase
8 06. Propiedades (@property)
9 07.
10 08. collections.namedtuple()
11 09.
12 Ep´ılogo
init () y
new ()
str () y
repr ()
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
19 / 230
01. Python’s super() considered super!
01. super()
La funci´on super() nos devuelve un objeto proxy
que delega llamadas a una superclase.
En su uso m´as b´asico y com´un, nos permite llamar a un
m´etodo definido en la clase base (es decir, de la que hemos
heredado) sin tener que nombrarlas expl´ıcitamente, ha-
ciendo nuestro c´odigo m´as sencillo y mantenible.
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
20 / 230
01. Algo que no funciona
01. super()
1
2
3
4
5
6
7
8
9
# encoding: UTF-8
class ListaLogger(list):
def append(self, x):
print "Intentando a~nadir", x
self.append(x)
numeros = ListaLogger()
numeros.append(7)
Intentando a~nadir 7
Intentando a~nadir 7
Intentando a~nadir 7
Intentando a~nadir 7
Intentando a~nadir 7
Intentando a~nadir 7
Intentando a~nadir 7
Intentando a~nadir 7
Intentando a~nadir 7
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
21 / 230
01. Hay que hacerlo as´ı
01. super()
1
2
3
4
5
6
7
8
9
10
# encoding: UTF-8
class ListaLogger(list):
def append(self, x):
print "A~nadiendo", x, "a la lista (¡ahora s´ı!)"
super(ListaLogger, self).append(x)
numeros = ListaLogger()
numeros.append(7)
print numeros
A~nadiendo 7 a la lista (¡ahora s´ı!)
[7]
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
22 / 230
01. Un segundo ejemplo
01. super()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Punto(object):
def __init__(self, x, y):
self.x = x
self.y = y
class Circulo(Punto):
def __init__(self, x, y, radio):
super(Circulo, self).__init__(x, y)
self.radio = radio
c = Circulo(3, 4, 5.5)
print "x:", c.x
print "y:", c.y
print "r:", c.radio
x: 3
y: 4
r: 5.5
V´ıctor Terr´on (IAA-CSIC)
Clases en Python: lo est´as haciendo mal
9 de noviembre de 2014
23 / 230
01. super() en Python 3000
01. super()
En Python 3 ya no es necesario especificar la clase actual.
1
2
3
4
5
6
7
8
class ListaLogger(list):
def append(self, x):
print("Esto tambi´en a~nade", x)
super().append(x)
numeros = ListaLogger([4, 5])
numeros.append(-1)
print(numeros)
Esto tambi´en a~nad
Comentarios de: Clases en Python: lo estás haciendo mal (0)
No hay comentarios