resueltos programacion poo orientada objetos multiple importar herencia ejercicios constructores clases __str__ __init__ python oop instance-variables

programacion - poo python 3



Python: ¿deberían inicializarse todas las variables miembro en__init__? (3)

Aquí hay un extracto de sololearn.com (un sitio gratuito para aprender Python)

"Las propiedades proporcionan una forma de personalizar el acceso a los atributos de la instancia. Se crean poniendo el decorador de propiedades sobre un método, lo que significa que cuando se accede al atributo de instancia con el mismo nombre que el método, se llamará al método en su lugar.

Un uso común de una propiedad es hacer un atributo de solo lectura ".

Ejemplo (también de sololearn.com):

class Pizza: def __init__(self, toppings): self.toppings = toppings @property def pineapple_allowed(self): return False pizza = Pizza(["cheese", "tomato"]) print(pizza.pineapple_allowed) pizza.pineapple_allowed = True

Resultado:

>>> False AttributeError: can''t set attribute >>>

Si var3 depende de var1 y var2, podrías hacer

class myClass: def __init__(self,var1,var2): self.var1=var1 self.var2=var2 @property def var3(self): return(self.var1+self.var2) #var3 depends on var1 and var2 m1=myClass(1,2) print(m1.var3) # var3 is 3

Var3 también se puede establecer en lo que quieras utilizando una función setter. Tenga en cuenta que puede evitar establecer var3 en un valor arbitrario al usar None.

class myClass2(object): def __init__(self,var1,var2): self.var1=var1 self.var2=var2 self._var3=None # None or an initial value that makes sense @property def var3(self): return(self._var3) @var3.setter def var3(self,value): self._var3=value m2=myClass(1,2) print(m2.var3) # var3 is none print(m2.var3(10)) # var3 is set to 10

Tal vez esto sea más una cuestión de estilo que técnica, pero tengo una clase python con varias variables miembro y quiero que funcione para que algunas de las variables miembro se inicialicen cuando el usuario crea una instancia de la clase (es decir, en la función __init__ ) y quiero que las otras variables miembro se definan a partir de los argumentos de las funciones miembro que se __init__ más tarde. Así que mi pregunta es si debo inicializar todas las variables miembro en la función __init__ (y establecer las que se definirán más adelante en valores ficticios) o inicializar algunas en la función __init__ y algunas en funciones posteriores. Me doy cuenta de que esto puede ser difícil de entender, así que aquí hay un par de ejemplos.

Este ejemplo tiene var3 puesto a 0 inicialmente en la función __init__ , luego establece el valor deseado más adelante en la función my_funct.

class myClass(object): def __init__(self,var1,var2): self.var1=var1 self.var2=var2 self.var3=0 def my_funct(self,var3): self.var3=var3

y en este ejemplo, var3 no está definido en absoluto en la función __init__

class myClass(object): def __init__(self,var1,var2): self.var1=var1 self.var2=var2 def my_funct(self,var3): self.var3=var3

No creo que de ninguna manera suponga una gran diferencia (tal vez una pequeña diferencia en el uso de la memoria). Pero me preguntaba si uno de estos se prefiere sobre el otro por alguna razón.


De hecho, desalentaría las variables de inicialización que no siempre se necesitan en __init__ a un valor predeterminado arbitrario.

Sí cuestiono tu uso de OO si este es el caso, pero estoy seguro de que hay un caso válido y entendible en el que __init__ no hará todo, y la clase querrá modificarse añadiendo atributos adicionales con otros métodos.

La forma correcta, en mi opinión, de probar si se configuró una variable mientras se ejecuta un método que podría querer usarla, sería usar hasattr . En este caso, esta es una forma válida de usar el método y la prueba simplemente cambia el comportamiento de una manera sensata.

Otra forma sería tratar de usarlo y manejar la excepción y proporcionar información amigable sobre lo que el usuario de su clase está haciendo mal. Esto es en el caso de que el método necesite que el atributo se establezca antes de ejecutarse.

es decir, hombre, usted inicializó la clase, pero necesita asegurarse de que exista el atributo z llamando al método z_init antes de ejecutar el método z_run .

Otra, podría decirse que es la manera más pitónica, sería simplemente documentar cómo usar el método en la cadena de documentación y luego dejar que la excepción vuele cuando se usa de forma incorrecta. Esto es lo suficientemente bueno para la primera implementación de algo y luego puede enfocarse en la próxima tarea. Esto está en la misma situación que la anterior, el método necesita que se establezca el atributo.

La razón por la que no me gusta la idea de inicializar variables a los valores predeterminados arbitrarios es que esto puede ser confuso (porque es arbitrario) y es ruido de línea.

Si el valor no es arbitrario y simplemente es un valor predeterminado que puede modificarse, debe utilizar un valor predeterminado en el método __init__ que se puede anular. También puede ser un estado inicial válido, que tampoco es arbitrario y debes establecerlo en el método __init__ .

Entonces, la verdadera respuesta es que depende , y probablemente debas evitarla y cuestionar tu uso de OO si estás haciendo esto agregando atributos en otros métodos o inicializando atributos a valores arbitrarios.

Si bien Simeon Visser dice que debe mantener su objeto en un estado constante, no tiene ninguna base para la coherencia basada en su ejemplo abstracto. Mientras Pylint advierte sobre este tipo de cosas, las advertencias de los programas de pelusas son simplemente para que un revisor de alto nivel pueda ser alertado de las cosas que generalmente indican el olor a código. Digo revisor de alto nivel porque un crítico real debe leer y comprender todo su código, y por lo tanto no necesita realmente Pylint.

Un ejemplo que rompe la regla de oro:

class Mutant(object): """A mutant!""" def __init__(self): """A mutant is born with only 1 eye and 1 mouth""" self.eyes = 1 self.mouth = 1 self.location = ''Montana'' def roll_to(self, location): """If they have limbs, running is less dangerous""" if hasattr(self, ''limbs''): print ''Your mutant broke its limbs off!!'' del self.limbs self.location = location def run_to(self, location): """If they don''t have limbs, running is not effective""" if not hasattr(self, ''limbs''): print ''Your mutant tries to run but he has no limbs.'' else: self.location = location def grow_limbs(self, number_of_limbs): """Ah, evolution!""" assert number_of_limbs > 0, ''Cannot grow 0 or less limbs...'' if hasattr(self, ''limbs''): self.limbs += number_of_limbs else: self.limbs = number_of_limbs


En la programación orientada a objetos, depende del desarrollador asegurarse de que un objeto esté siempre en un estado consistente después de la instanciación y después de que finalice un método. Aparte de eso, eres libre de desarrollar la clase como desees (teniendo en cuenta ciertos principios con subclassing / overriding, etc.).

Una herramienta como Pylint avisará cuando establezca variables de instancia fuera de __init__ . Se puede argumentar que establecer todas las variables de instancia en __init__ es más __init__ pero no es una regla que deba cumplirse en todo momento.