Re: Re: duda acerca de self como argumento de métodos
Medardo Rodriguez
med.swl en gmail.com
Mar Mayo 27 18:35:58 CEST 2008
2008/5/27 Milton Galo Patricio Inostroza Aguilera <minoztro en gmail.com>:
> bueno específicamente me dijeron esto:
>
> """
> ...
> en todo lenguaje OO que sirve hoy en dia, el self es un parametro
> implicito ...
> """
Esta frase es muy pretenciosa, hasta donde sé hay más de 200 lenguajes
OO, y todos le deben servir a alguien. También implica acusar al
Python de no servir, y para mi que sirve más como lenguaje que el
Java, C#, Delphi para las aplicaciones más comunes hoy. Pero no quiero
generar flames con esto, sólo compartir un poco mis experiencias.
Como aporte, uno de mis alumnos en mi curso de programación el año
pasado me presentó la siguiente página de la Wiki:
http://en.wikipedia.org/wiki/Circle-ellipse_problem
Es un artículo pseudo-científico. Me insulté mucho, sobre todo por los
siguientes dos motivos:
* Hacen referencia a una supuesta violación de un axioma de Barbara
Liskov[1] que en mi opinión es lo mejor en desarrollo científico de la
programación como ciencia de los últimos 20 años.
* Basan el análisis en algo muy superficial tomando como base lo
ineficiente de algunos lenguajes de programación para expresar modelos
tan simples como éste.
Mi respuesta fue:
«En 8vo grado mi profesor de matemáticas me digo que los círculos son
elipses con distancia focal igual a cero. La primera parte de este
predicado implica una relación de herencia entre clases: la clase
*Circle* hereda de la clase *Ellipse*. La segunda parte es una
invariante de clase[2].» No sabía de qué hablaba cuando le mencioné la
última estructura. Le dije, «estudia al menos la teoría de Bertrand
Meyer que está considerado pionero de la Teoría de Tipos y de la
Programación Basada en restricciones.» Luego le enfoqué el problema
desde otro punto de vista: el de un editor vectorial, donde una podía
adicionar un objeto de la clase *Ellipse* y la barra de estados
debería mostrarme el nombre de la clase del objeto selecionado y el
ancho y el alto de éste. Le dije, «si arrastro por una de las esquinas
a una elipse hasta que su alto y ancho sean iguales ¿qué nombre de
clase debería mostrarme?» Sin pensarlo mucho dijo «Círculo». Le dije
«un objeto mutó, cambió de clase» y le propuse programar eso en C#
(lenguaje que usaba). Se dio cuenta que le sería casi imposible
lograrlo y me dijo que no era válido que un objeto mutara de clase. Le
dije «bueno, a mi me parece muy normal (y a mi mamá, que no sabe nada
de programación, también) que si le cambio el tamaño a una elipse
pueda convertirse en un círculo; lo que pasa es que ustedes no ven la
programación como una forma de representar la realidad, si no
quisieran modificar la realidad a lo arquetípico de Platón para que
se adapte a la programación que usan».
Acto seguido me senté y muy rápido le programé lo siguiente en Python:
<code language="python">
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# Copyright (C) 2008, Medardo Rodriguez
# http://en.wikipedia.org/wiki/Circle-ellipse_problem
class Shape(object):
def __init__(self, x, y):
self.x = x
self.y = y
class SizeableShape(Shape):
def __init__(self, x, y, dx, dy):
Shape.__init__(self, x, y)
self.SetSize(dx, dy)
def SetSize(self, dx, dy):
self.dx = dx
self.dy = dy
def _IsSquarish(self):
Epsilon = 1E-10
return abs(self.dx - self.dy) < Epsilon
class MutableShape(SizeableShape):
def _Mutate(self, _class): # analize if some checks are needed here
self.__class__ = _class
def __SetSize(self, dx, dy):
"""This is not intended to be used. It's only a common solution for
inheritance relationships fulfilling implied conditions.
(Ellipse, Circle) and (Rectangle, Square) are two examples."""
SizeableShape.SetSize(self, dx, dy)
subclasses = self.__class__.__subclasses__()
IsSuperClase = (len(subclasses) > 0) # (Ellipse, Rectangle)
NeedMutation = (IsSuperClase == self._IsSquarish())
if NeedMutation:
if IsSuperClase:
_class = subclasses[0]
else:
_class = self.__class__.__base__
self._Mutate(_class)
class Ellipse(MutableShape):
def SetSize(self, dx, dy):
MutableShape.SetSize(self, dx, dy)
if self._IsSquarish() and (type(self) is Ellipse):
self._Mutate(Circle)
class Circle(Ellipse):
def __init__(self, x, y, radius):
diameter = 2*radius
Ellipse.__init__(self, x, y, diameter, diameter)
def SetSize(self, dx, dy):
Ellipse.SetSize(self, dx, dy)
if not self._IsSquarish() and (type(self) is Circle):
self._Mutate(Ellipse)
class Rectangle(MutableShape):
def SetSize(self, dx, dy):
MutableShape.SetSize(self, dx, dy)
if self._IsSquarish() and (type(self) is Rectangle):
self._Mutate(Square)
class Square(Rectangle):
def __init__(self, x, y, width):
Rectangle.__init__(self, x, y, width, width)
def SetSize(self, dx, dy):
Rectangle.SetSize(self, dx, dy)
if not self._IsSquarish() and (type(self) is Square):
self._Mutate(Rectangle)
class Point(Shape): pass
if __name__ == '__main__':
for code in ('ce = Circle(0, 0, 10)', 'ce.SetSize(5, 6)',
'ce.SetSize(15, 15)'):
exec code
print '>>> %s' % code
for cls in [Circle, Ellipse]:
print '%s: %s' % (cls.__name__, isinstance(ce, cls))
print
</code>
Aún espero por que alguien me haga algo como esto en C#, Java u otro
lenguaje popular, de esos que «sirven».
Alguna vez poniendo este ejemplo dije «El Python no es perfecto, pero
evidentemente es mejor que otros para modelar más cercano a cómo
razonamos, y ésta es lo correcto en programación»
Saludos
[1] http://en.wikipedia.org/wiki/Liskov_substitution_principle
[2] http://en.wikipedia.org/wiki/Class_invariant
_______________________________________________
Lista de correo Python-es
http://listas.aditel.org/listinfo/python-es
FAQ: http://listas.aditel.org/faqpyes
Más información sobre la lista de distribución Python-es