¿Por qué el parámetro de "nombre" en __setattr__ incluye la clase, pero __getattr__ no?

StackOverflow https://stackoverflow.com/questions/2386418

  •  24-09-2019
  •  | 
  •  

Pregunta

El siguiente código:

class MyClass():
    def test(self):
        self.__x = 0

    def __setattr__(self, name, value):
        print name

    def __getattr__(self, name):
        print name
        raise AttributeError(name)

x = MyClass()
x.test()
x.__y

Salidas:

_MyClass__x
__y
Traceback (most recent call last):
...
AttributeError: __y

La documentación es completamente inútil que indica que el "nombre" es el "nombre del atributo", pero por alguna razón es diferente dependiendo de si lo está configurando o obteniéndolo.

Lo que quiero saber es:

  • ¿Estoy haciendo algo fundamentalmente mal aquí?
  • Como lo consigo x en el primer caso en lugar de _MyClass__x?
¿Fue útil?

Solución

El doble subrayador invoca el nombre de la gestión. Si no necesitas nombraciones, no uses Double Undocore

¿Cuál es el significado de una sola y una doble base antes de un nombre de objeto?

Desde el Python Docs

9.6. Variables privadas

Variables de instancia "privadas" a las que no se puede acceder, excepto desde el interior de un objeto, no existen en Python. Sin embargo, hay una convención seguida por la mayoría del código de Python: un nombre prefijado con un bajo (p. Ej. _spam) debe tratarse como una parte no pública de la API (ya sea una función, un método o un miembro de datos). Debe considerarse un detalle de implementación y sujeto a cambios sin previo aviso.

Dado que hay un caso de uso válido para miembros privados de clase (es decir, para evitar nombres de nombres con nombres definidos por subclases), existe un soporte limitado para dicho mecanismo, llamado Nombre Mangling. Cualquier identificador del formulario __spam (al menos dos subrayadores principales, como máximo uno, un bajo bajo) se reemplaza textualmente con _classname__spam, donde ClassName es el nombre de clase actual con un subrayador (s) principal despojado. Esta gestión se realiza sin tener en cuenta la posición sintáctica del identificador, siempre que ocurra dentro de la definición de una clase.

Tenga en cuenta que las reglas de gestión están diseñadas principalmente para evitar accidentes; Todavía es posible acceder o modificar una variable que se considera privada. Esto incluso puede ser útil en circunstancias especiales, como en el depurador.

Observe que el código pasó a exec, eval() o execfile() no considera que el nombre de clase de la clase invocador sea la clase actual; Esto es similar al efecto de la declaración global, cuyo efecto también está restringido al código que se compila juntos. La misma restricción se aplica a getattr(), setattr() y delattr(), así como cuando se hace referencia __dict__ directamente.

Otros consejos

No estoy seguro exactamente por qué ocurre esto, pero si usas _x más bien que __x Funciona como era de esperar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top