Atributos que no son identificadores de python válidos

El método habitual de acceso a los atributos requiere que los nombres de los atributos sean identificadores de python válidos .

Pero los atributos no tienen que ser identificadores de python válidos:

>>> class Thing: ... def __init__(self): ... setattr(self, '0potato', 123) ... >>> t = Thing() >>> Thing.__getattribute__(t, '0potato') 123 >>> getattr(t, '0potato') 123 

Por supuesto, t.0potato sigue siendo un SyntaxError , pero el atributo todavía existe:

 >>> vars(t) {'0potato': 123} 

¿Cuál es la razón para que esto sea permisible? ¿Existe realmente algún caso de uso válido para los atributos con espacios, cadenas vacías, palabras clave reservadas con python, etc.? Pensé que la razón era que los atributos eran solo claves en el objeto / espacio de nombres dict, pero esto no tiene sentido porque otros objetos que son claves de dict válidos no están permitidos:

 >>> setattr(t, ('tuple',), 321) TypeError: attribute name must be string, not 'tuple' 

Entonces, para responder a la pregunta del caso de uso, observando el razonamiento detrás de cómo funciona Python en las referencias de los comentarios anteriores, podemos inferir algunas de las situaciones que podrían hacer útil esta peculiaridad de Pythonic.

  1. Desea que un objeto tenga un atributo al que no se pueda acceder con notación de puntos, por ejemplo, para protegerlo del usuario ingenuo. (Citando a Guido: “algunas personas pueden usar esto para ocultar el estado al que no quieren acceso mediante la notación de atributo regular (x.foo)”. Por supuesto, continúa diciendo, “pero eso me parece un abuso del espacio de nombres para mí”. , y hay muchas otras formas de administrar dicho estado “.
  2. Desea que los nombres de atributo de un objeto se correspondan con datos externos sobre los que no tiene control. Por lo tanto, debe poder utilizar las cadenas que aparecen en los datos externos como un nombre de atributo, incluso si coincide con una palabra reservada de Python o si contiene espacios o guiones incrustados, etc.

Los detalles de un comentario en la publicación responden completamente a esta pregunta, así que la publico como respuesta:

Guido dice:

… es una característica que puede usar cualquier cadena arbitraria con getattr () y setattr (). Sin embargo, estas funciones deben (¡y lo hacen!) Rechazar las no cadenas.

Los posibles casos de uso incluyen ocultar atributos del acceso punteado regular y hacer atributos en correspondencia con fonts de datos externas (que pueden entrar en conflicto con las palabras clave de Python). Entonces, el argumento parece ser que simplemente no hay una buena razón para prohibirlo.

En cuanto a una razón para no permitir cadenas, esto parece ser una restricción sensata que garantiza un mayor rendimiento de la implementación:

Aunque los dictados de Python ya tienen algunas optimizaciones de solo cadenas, solo se adaptan dinámicamente a un enfoque más genérico y ligeramente más lento una vez que aparece la primera cadena que no es clave.