round example built python methods python-3.x setattr

python - example - ¿Por qué setattr falla en un método vinculado



round python 3 (2)

La respuesta corta: no hay forma de agregar atributos personalizados a los métodos enlazados.

La respuesta larga sigue.

En Python, hay objetos de función y objetos de método . Cuando defines una clase, la declaración def crea un objeto de función que vive dentro del espacio de nombres de la clase:

>>> class c: ... def m(self): ... pass ... >>> c.m <function m at 0x025FAE88>

Los objetos de función tienen un atributo especial __dict__ que puede contener atributos definidos por el usuario:

>>> c.m.i = 0 >>> c.m.__dict__ {''i'': 0}

Los objetos de método son bestias diferentes. Son objetos pequeños que solo contienen una referencia al objeto de función correspondiente ( __func__ ) y uno a su objeto de host ( __self__ ):

>>> c().m <bound method c.m of <__main__.c object at 0x025206D0>> >>> c().m.__self__ <__main__.c object at 0x02625070> >>> c().m.__func__ <function m at 0x025FAE88> >>> c().m.__func__ is c.m True

Los objetos de método proporcionan un __getattr__ especial que reenvía el acceso de atributo al objeto de función:

>>> c().m.i 0

Esto también es cierto para la propiedad __dict__ :

>>> c().m.__dict__[''a''] = 42 >>> c.m.a 42 >>> c().m.__dict__ is c.m.__dict__ True

Sin embargo, los atributos de configuración siguen las reglas predeterminadas, y como no tienen su propio __dict__ , no hay forma de establecer atributos arbitrarios.

Esto es similar a las clases definidas por el usuario que definen __slots__ y no __dict__ slot, cuando intenta establecer un intervalo no existente se genera un AttributeError (consulte los documentos en __slots__ para obtener más información):

>>> class c: ... __slots__ = (''a'', ''b'') ... >>> x = c() >>> x.a = 1 >>> x.b = 2 >>> x.c = 3 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: ''c'' object has no attribute ''c''

A continuación, setattr tiene éxito en la primera invocación, pero falla en la segunda, con:

AttributeError: ''method'' object has no attribute ''i''

¿Por qué es esto? ¿Existe alguna forma de establecer un atributo en un método de modo que solo exista en una instancia, no para cada instancia de la clase?

class c: def m(self): print(type(c.m)) setattr(c.m, ''i'', 0) print(type(self.m)) setattr(self.m, ''i'', 0)

Python 3.2.2


P: "¿Hay alguna manera de establecer un atributo en un método de modo que solo exista en una instancia, no para cada instancia de la clase?"

A: Sí:

class c: def m(self): print(type(c.m)) setattr(c.m, ''i'', 0) print(type(self)) setattr(self, ''i'', 0)

La variable estática de las funciones en la publicación a la que se vincula no es útil para los métodos. Establece un atributo en la función para que este atributo esté disponible la próxima vez que se llame a la función, para que pueda crear un contador o lo que sea.

Pero los métodos tienen una instancia de objeto asociada a ellos (uno mismo). Por lo tanto, no es necesario establecer atributos en el método, ya que simplemente puede configurarlo en la instancia. De hecho, es exactamente para lo que es la instancia.

La publicación a la que se vincula muestra cómo hacer una función con una variable estática. Diría que en Python hacerlo sería una equivocación. En su lugar, mire esta respuesta: ¿Cuál es el equivalente Python de las variables estáticas dentro de una función?

Esa es la manera de hacerlo en Python de una manera que sea clara y fácilmente comprensible. Usas una clase y la haces invocable. Establecer atributos en las funciones es posible y probablemente haya casos en los que sea una buena idea, pero en general terminará confundiendo a las personas.