poo - llamar metodo de otra clase python
¿Qué es un caso de uso de ejemplo para un método de clase Python? (6)
Bueno __new__
es un método de clase bastante importante. Es de donde generalmente provienen las instancias
así que dict()
llama dict.__new__
por supuesto, pero hay otra forma práctica de hacer dicts a veces, que es el classmethod dict.fromkeys()
p.ej.
>>> dict.fromkeys("12345")
{''1'': None, ''3'': None, ''2'': None, ''5'': None, ''4'': None}
He leído para qué son los métodos de clase en Python? pero los ejemplos en esa publicación son complejos. Estoy buscando un ejemplo claro, simple y escueto de un caso de uso particular para classmethods en Python.
¿Puedes nombrar un caso de uso de ejemplo pequeño y específico donde un método de clase de Python sería la herramienta adecuada para el trabajo?
Encuentro que con mayor frecuencia uso @classmethod
para asociar un fragmento de código con una clase, para evitar la creación de una función global, para los casos en que no requiera una instancia de la clase para usar el código.
Por ejemplo, podría tener una estructura de datos que solo considere una clave válida si cumple con algún patrón. Es posible que desee utilizar esto desde dentro y fuera de la clase. Sin embargo, no quiero crear otra función global:
def foo_key_is_valid(key):
# code for determining validity here
return valid
Prefiero agrupar este código con la clase a la que está asociado:
class Foo(object):
@classmethod
def is_valid(cls, key):
# code for determining validity here
return valid
def add_key(self, key, val):
if not Foo.is_valid(key):
raise ValueError()
..
# lets me reuse that method without an instance, and signals that
# the code is closely-associated with the Foo class
Foo.is_valid(''my key'')
La razón más importante para usar un @classmethod
es en un constructor alternativo que se pretende heredar. Esto puede ser muy útil en polimorfismo. Un ejemplo:
class Shape(object):
# this is an abstract class that is primarily used for inheritance defaults
# here is where you would define classmethods that can be overridden by inherited classes
@classmethod
def from_square(cls, square):
# return a default instance of cls
return cls()
Observe que Shape
es una clase abstracta que define un método de clase from_square
, ya que Shape
no está realmente definido, realmente no sabe cómo derivarse de un Square
por lo que simplemente devuelve una instancia predeterminada de la clase.
Las clases heredadas pueden definir sus propias versiones de este método:
class Square(Shape):
def __init__(self, side=10):
self.side = side
@classmethod
def from_square(cls, square):
return cls(side=square.side)
class Rectangle(Shape):
def __init__(self, length=10, width=10):
self.length = length
self.width = width
@classmethod
def from_square(cls, square):
return cls(length=square.side, width=square.side)
class RightTriangle(Shape):
def __init(self, a=10, b=10):
self.a = a
self.b = b
self.c = ((a*a) + (b*b))**(.5)
@classmethod
def from_square(cls, square):
return cls(a=square.length, b=square.width)
class Circle(Shape):
def __init__(self, radius=10):
self.radius = radius
@classmethod
def from_square(cls, square):
return cls(radius=square.length/2)
El uso le permite tratar polimórficamente todas estas clases desinstaladas
square = Square(3)
for polymorphic_class in (Square, Rectangle, RightTriangle, Circle):
this_shape = polymorphic_class.from_square(square)
Esto está bien y muy bien, podría decir, pero ¿por qué no podría usar el @staticmethod
para lograr este mismo comportamiento polimórfico?
class Circle(Shape):
def __init__(self, radius=10):
self.radius = radius
@staticmethod
def from_square(square):
return Circle(radius=square.length/2)
La respuesta es que podrías, pero no obtienes los beneficios de la herencia porque se debe llamar a Circle
explícitamente en el método. Es decir, si lo llamo desde una clase heredada sin anulación, todavía obtendría Circle
cada vez.
Observe lo que se gana cuando defino otra clase de forma que realmente no tiene ninguna lógica from_square personalizada:
class Hexagon(Shape):
def __init__(self, side=10):
self.side = side
# note the absence of classmethod here, this will use from_square it inherits from shape
Aquí puede dejar el @classmethod
undefined y usará la lógica de Shape.from_square
mientras retiene quién es cls
y devuelve la forma apropiada.
square = Square(3)
for polymorphic_class in (Square, Rectangle, RightTriangle, Circle, Hexagon):
this_shape = polymorphic_class.from_square(square)
Métodos de ayuda para la inicialización:
class MyStream(object):
@classmethod
def from_file(cls, filepath, ignore_comments=False):
with open(filepath, ''r'') as fileobj:
for obj in cls(fileobj, ignore_comments):
yield obj
@classmethod
def from_socket(cls, socket, ignore_comments=False):
raise NotImplemented # Placeholder until implemented
def __init__(self, iterable, ignore_comments=False):
...
No sé, ¿algo así como los métodos de constructor con nombre?
class UniqueIdentifier(object):
value = 0
def __init__(self, name):
self.name = name
@classmethod
def produce(cls):
instance = cls(cls.value)
cls.value += 1
return instance
class FunkyUniqueIdentifier(UniqueIdentifier):
@classmethod
def produce(cls):
instance = super(FunkyUniqueIdentifier, cls).produce()
instance.name = "Funky %s" % instance.name
return instance
Uso:
>>> x = UniqueIdentifier.produce()
>>> y = FunkyUniqueIdentifier.produce()
>>> x.name
0
>>> y.name
Funky 1
in class MyClass(object):
''''''
classdocs
''''''
obj=0
x=classmethod
def __init__(self):
''''''
Constructor
''''''
self.nom=''lamaizi''
self.prenom=''anas''
self.age=21
self.ville=''Casablanca''
if __name__:
ob=MyClass()
print(ob.nom)
print(ob.prenom)
print(ob.age)
print(ob.ville)