Atributos de clase Metamorfosis

Una breve nota de la serie "Fuiste advertido".

Cambiar de lenguajes de programación clásicos a Python trae muchas sorpresas.
Lee la documentación:
En términos generales, las variables de instancia son para datos únicos de cada instancia y las variables de clase son para atributos y métodos compartidos por todas las instancias de la clase
Tratemos de jugar

class Vessel: #class attribute vtype = "boat" #instance attribute def __init__(self, name): self.name = name #    def __str__(self): res= '>>' for a in inspect.getmembers( self): if not a[0].startswith("__"): res += f"{a[0]}={a[1]:<14}" for a in inspect.getmembers( self.__class__): if not a[0].startswith("__"): res += f"__class__.{a[0]}={a[1]:<14}" return res 


Cree dos objetos, verifique los valores de todos los atributos:

 Iowa = Vessel("Iowa") Drum=Vessel("Drum") printAttr(Iowa, Drum) >>name=Iowa vtype=boat __class__.vtype=boat >>name=Drum vtype=boat __class__.vtype=boat 

Hasta ahora, como se esperaba.

Tratemos de cambiar vtype: esto se puede hacer de dos maneras, que son esencialmente una sintaxis diferente de la misma

 Vessel.vtype = "USS boat" printAttr(Iowa, Drum) >>name=Iowa vtype=USS boat __class__.vtype=USS boat >>name=Drum vtype=USS boat __class__.vtype=USS boat Iowa.__class__.vtype = 'USS WW2 Boat' printAttr(Iowa, Drum) >>name=Iowa vtype=USS WW2 Boat __class__.vtype=USS WW2 Boat >>name=Drum vtype=USS WW2 Boat __class__.vtype=USS WW2 Boat 

Y nuevamente, todo está en orden.

Ahora intentemos hacer lo mismo a través del atributo del objeto.

 Drum.vtype = 'submarine' printAttr(Iowa, Drum) >>name=Iowa vtype=USS WW2 Boat __class__.vtype=USS WW2 Boat >>name=Drum vtype=submarine __class__.vtype=USS WW2 Boat 

Y aquí está la primera sorpresa: a pesar de que vtype es un atributo de una clase, de repente se convierte en un atributo de un objeto.

Comprobar:

 Vessel.vtype = "NAVY Museum" >>name=Iowa vtype=NAVY Museum __class__.vtype=NAVY Museum >>name=Drum vtype=submarine __class__.vtype=NAVY Museum 

que tal si ...

  del Drum.vtype >>name=Iowa vtype=NAVY Museum __class__.vtype=NAVY Museum >>name=Drum vtype=NAVY Museum __class__.vtype=NAVY Museum 

Y de nuevo un atributo de clase.

La siguiente expresión ya no pasa

 del Drum.vtype printAttr(Iowa, Drum) del Drum.vtype AttributeError: vtype 

Y el último ejemplo emula la anulación de clases y elimina el atributo vtype.

 Drum.vtype = 'submarine' del Vessel.vtype printAttr(Iowa, Drum) >>name=Iowa >>name=Drum vtype=submarine 

Si comienza a tratar con el espacio de nombres, este comportamiento se vuelve comprensible.
Sin embargo, para los programadores que anteriormente trabajaban con lenguajes normales, esto al menos parece extraño. Y si hablamos de grandes proyectos respaldados por varias generaciones de desarrolladores, esto puede resultar en un incumplimiento de los plazos, etc.

Teniendo en cuenta el concepto de Python de que todo está abierto para todos, ¿por qué no hacer acceso a los atributos "geniales" solo a través de __class__ o su análogo. En mi opinión, esto al menos de alguna manera protegería contra sorpresas y me haría pensar 10 veces antes de asignar algo a los atributos de clase a nivel de objeto.

Actualización: Text PrintAttr

 def printAttr(*o): for a in o: print(a) 

Source: https://habr.com/ru/post/es427065/


All Articles