una programacion otra orientada objetos metodos metodo llamar instanciar herencia ejemplo como clases clase python class immutability mutable

python - programacion - son las clases definidas por el usuario mutables



programacion orientada a objetos python pdf (4)

Digamos que quiero crear una clase para car , tractor y boat . Todas estas clases tienen una instancia de engine y quiero hacer un seguimiento de todos los motores en una sola lista. Si entiendo correctamente si el objeto motor es mutable, puedo almacenarlo como un atributo de car y también la misma instancia en una lista.

No puedo rastrear ninguna información sólida sobre si las clases definidas por el usuario son mutables y si hay una opción para elegir cuando las define, ¿alguien puede arrojar algo de luz?


Creo que estás confundiendo la mutabilidad con la forma en que python guarda las referencias. Considera:

class Foo(object): pass t = (1,2,Foo()) # t is a tuple, :. t is immutable b = a[2] # b is an instance of Foo b.foo = "Hello" # b is mutable. (I just changed it) print (hash(b)) # b is hashable -- although the default hash isn''t very useful d = {b : 3} # since b is hashable, it can be used as a key in a dictionary (or set). c = t # even though t is immutable, we can create multiple references to it. a = [t] # here we add another reference to t in a list.

Ahora a su pregunta sobre cómo obtener / almacenar una lista de motores a nivel mundial: hay algunas maneras diferentes de hacerlo, aquí hay una:

class Engine(object): def __init__(self, make, model): self.make = make self.model = model class EngineFactory(object): def __init__(self,**kwargs): self._engines = kwargs def all_engines(self): return self._engines.values() def __call__(self,make, model): """ Return the same object every for each make,model combination requested """ if (make,model) in _engines: return self._engines[(make,model)] else: a = self._engines[(make,model)] = Engine(make,model) return a engine_factory = EngineFactory() engine1 = engine_factory(''cool_engine'',1.0) engine2 = engine_factory(''cool_engine'',1.0) engine1 is engine2 #True !!! They''re the same engine. Changing engine1 changes engine2

El ejemplo anterior podría mejorarse un poco haciendo que EngineFactory._engines dict almacene objetos weakref.ref lugar de almacenar referencias reales a los objetos. En ese caso, debe asegurarse de que la referencia esté viva (no se haya recogido basura) antes de devolver una nueva referencia al objeto.


Las clases de usuario se consideran mutables. Python no tiene atributos (absolutamente) privados, por lo que siempre puede cambiar una clase al acceder a las partes internas.

Para usar su clase como clave en un dict o almacenarlos en un set , puede definir un método .__hash__() y un método .__eq__() , haciendo la promesa de que su clase es inmutable. Generalmente, usted diseña su API de clase para no modificar el estado interno después de la creación en tales casos.

Por ejemplo, si sus motores están definidos de forma única por su id, puede usar eso como base de su hash:

class Engine(object): def __init__(self, id): self.id = id def __hash__(self): return hash(self.id) def __eq__(self, other): if isinstance(other, self.__class__): return self.id == other.id return NotImplemented

Ahora puede usar instancias de clase Engine en conjuntos:

>>> eng1 = Engine(1) >>> eng2 = Engine(2) >>> eng1 == eng2 False >>> eng1 == eng1 True >>> eng1 == Engine(1) True >>> engines = set([eng1, eng2]) >>> engines set([<__main__.Engine object at 0x105ebef10>, <__main__.Engine object at 0x105ebef90>]) >>> engines.add(Engine(1)) >>> engines set([<__main__.Engine object at 0x105ebef10>, <__main__.Engine object at 0x105ebef90>])

En la muestra anterior, agregué otra instancia de Engine(1) al conjunto, pero se reconoce que ya está presente y el conjunto no cambió.

Tenga en cuenta que, en lo que respecta a las listas, la implementación .__eq__() es la más importante. las listas no se preocupan si un objeto es mutable o no, pero con el método .__eq__() en su lugar puede probar si un motor dado ya está en una lista:

>>> Engine(1) in [eng1, eng2] True


Todos los objetos (con la excepción de unos pocos en la biblioteca estándar, algunos que implementan mecanismos especiales de acceso usando cosas como descriptores y decoradores, o algunos implementados en C) son mutables. Esto incluye instancias de clases definidas por el usuario, clases en sí mismas e incluso los objetos tipo que definen las clases. Incluso puede mutar un objeto de clase en tiempo de ejecución y hacer que las modificaciones se manifiesten en instancias de la clase creada antes de la modificación. En general, las cosas solo son inmutables por convención en Python si cavas lo suficientemente profundo.


EDITAR: Esto es conceptualmente incorrecto, el objeto inmutable en Python puede arrojar algo de luz sobre por qué.

class Engine(): def __init__(self, sn): self.sn = sn a = Engine(42) b = a print (a is b)

imprime True .