Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

246
Visualizações
*¿Por qué* object() no admite `setattr`, pero las clases derivadas sí?

Hoy me topé con el siguiente comportamiento:

 class myobject(object): """Should behave the same as object, right?""" obj = myobject() obj.a = 2 # <- works obj = object() obj.a = 2 # AttributeError: 'object' object has no attribute 'a'

Quiero saber cuál es la lógica detrás del diseño del lenguaje para que se comporte de esta manera, porque me parece totalmente paradójico. Rompe mi intuición de que si creo una subclase, sin modificaciones, debería comportarse igual que la clase principal.


EDITAR: muchas de las respuestas sugieren que esto se debe a que queremos poder escribir clases que funcionen con __slots__ en lugar de __dict__ por razones de rendimiento. Sin embargo, podemos hacer:

 class myobject_with_slots(myobject): __slots__ = ("x",) obj = myobject_with_slots() obj.x = 2 obj.a = 2 assert "a" in obj.__dict__ # ✔ assert "x" not in obj.__dict__ # ✔

Entonces, parece que podemos tener __slots__ y __dict__ al mismo tiempo, entonces, ¿por qué el object no permite ambos, pero las subclases uno a uno sí?

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Porque las clases derivadas tampoco son necesariamente compatibles con setattr .

 class myobject(object): """Should behave the same as object!""" __slots__ = () obj = myobject() obj.a = 2 # <- works the same as for object

Dado que todos los tipos se derivan de object , la mayoría de los tipos integrados, como list , también son ejemplos.

La asignación de atributos arbitrarios es algo que las subclases de object pueden admitir, pero no todos lo hacen. Por lo tanto, la clase base común tampoco admite esto .


La compatibilidad con atributos arbitrarios suele estar respaldada por la llamada ranura __dict__ . Este es un atributo fijo que contiene un dict literal 1 para almacenar cualquier par de atributo-valor.

De hecho, uno puede definir manualmente la ranura __dict__ para obtener compatibilidad con atributos arbitrarios.

 class myobject(object): """Should behave the same as object, right?""" __slots__ = ("__dict__",) obj = myobject() obj.a = 2 # <- works! print(obj.__dict__) # {'a': 2}

La conclusión de esta demostración es que los atributos fijos son en realidad el "comportamiento base" de Python; el soporte de atributos arbitrarios se construye en la parte superior cuando es necesario .

Agregar atributos arbitrarios para subtipos de object de manera predeterminada brinda una experiencia de programación más simple. Sin embargo, seguir admitiendo atributos fijos para subtipos de object permite un mejor uso y rendimiento de la memoria.

Modelo de datos: __slots__

El espacio ahorrado [por __slots__ ] sobre el uso de __dict__ puede ser significativo. La velocidad de búsqueda de atributos también se puede mejorar significativamente.

Tenga en cuenta que es posible definir clases con atributos fijos y atributos arbitrarios. Los atributos fijos se beneficiarán del diseño y el rendimiento mejorados de la memoria; dado que no se almacenan en el __dict__ , su sobrecarga de memoria 2 es menor, pero aún cuesta.


1 Las implementaciones de Python pueden usar diferentes tipos optimizados para __dict__ siempre que se comporten como un dict .

2 Para que su búsqueda basada en hash funcione de manera eficiente con pocas colisiones, un dict debe ser mayor que la cantidad de elementos que almacena.

over 4 years ago · Santiago Trujillo Relatório

0

Considere este código:

 class A: __slots__ = () class B(A): __slots__ = ("x", "y") b = B() bz = 1 # AttributeError

__slots__ = ("x", "y") significa que las instancias B no tienen un __dict__ y solo pueden tener los atributos x e y . Esto es bueno para el rendimiento.

Si elimina los __slots__ de A , las instancias de A obtienen un __dict__ , lo que significa que también lo hacen sus subclases, particularmente B . Esto reduce la eficacia de __slots__ para mejorar el rendimiento.

Debido a que object es una superclase de todas las clases, puede considerarlo como A aquí, con __slots__ = () y sin __dict__ para que otras clases también puedan evitar tener un __dict__ y beneficiarse plenamente de __slots__ personalizados.

over 4 years ago · Santiago Trujillo Relatório

0

Respuesta corta

object() por defecto no tiene un diccionario de atributos ( __dict__ ). Permite que la clase object() y cualquier cosa que herede de ella guarde unos pocos bytes.

por que es tan importante?

Cada clase en Python hereda de object() . Las clases como str , dict , tuple e int se usan sin cesar tanto interna como externamente.

Tener un diccionario de instancias significa que cada objeto en Python será más grande (consumirá más memoria) y más lento (cada atributo provocará una búsqueda en el diccionario).

Para mejorar la flexibilidad, de forma predeterminada, las clases creadas por el usuario vienen con una instancia __dict__ . Nos permite parchear instancias, enganchar métodos, inyectar dependencias dinámicamente y ofrece una cantidad infinita de beneficios diferentes. Es lo que le da a Python su fuerza como lenguaje de programación dinámico y una de las principales razones de su éxito.

Para evitar la creación de uno, puede configurar __slots__ así:

 class A: __slots__ = () A().abc = 123 # Will throw an error

No tener un diccionario de instancias significa que el acceso a los atributos regulares puede omitir la búsqueda __dict__ . El acceso más rápido a los atributos conduce a una gran mejora general en el tiempo de ejecución de Python, pero reducirá la flexibilidad en el uso de su clase.

La forma en que funciona la búsqueda de atributos sin usar __dict__ está fuera del alcance de la pregunta. Puede leer más sobre __slots__ en la documentación .


Para tu segunda pregunta:

Cualquier clase creada por el usuario que no tenga __slots__ tiene un diccionario de instancias ( __dict__ ).

Si lo subclasifica, no puede agregar __slots__ y eliminar el diccionario de la clase principal, ya existe.

Tener __slots__ y un diccionario elimina la mayoría de las ventajas de usar __slots__ que ahorra espacio y evita la creación de un diccionario.

 >>> import sys >>> class A: ... pass ... >>> class B: ... __slots__ = () ... >>> sys.getsizeof(A()) 48 >>> sys.getsizeof(B()) 32 >>> class C(A): ... __slots__ = () ... >>> sys.getsizeof(C()) 48 >>> C.__dict__ mappingproxy({'__module__': '__main__', '__slots__': (), '__doc__': None})
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda