Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

449
Vistas
Strange behaviour when mixing abstractmethod, classmethod and property decorators

I've been trying to see whether one can create an abstract class property by mixing the three decorators (in Python 3.9.6, if that matters), and I noticed some strange behaviour.

Consider the following code:

from abc import ABC, abstractmethod

class Foo(ABC):
    @classmethod
    @property
    @abstractmethod
    def x(cls):
        print(cls)
        return None

class Bar(Foo):
    @classmethod
    @property
    def x(cls):
        print("this is executed")
        return super().x

This outputs

this is executed
<class '__main__.Bar'>

This means that somehow, Bar.x ends up being called.

PyCharm warns me that Property 'self' cannot be deleted. If I reverse the order of @classmethod and @property, Bar.x is not called, but I still get the same warning, and also another one: This decorator will not receive a callable it may expect; the built-in decorator returns a special object (this also appears whenever I put @property above @classmethod).

Removing any of the three decorators (with the appropriate changes: adding () when removing @property or changing cls to self when removing @classmethod) also prevents Bar.x from being called.

I suppose all of this means that it's probably just a bad idea to directly mix those decorators (as indicated by discussion about class properties in other threads here).

Neverthless, I am curious: what is happening here? Why is Bar.x called?

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

You can try raising an exception in Bar.x. This way you can see where it is called.

It should lead you to abc.py in the standard library, specifically the line _abc_init(cls). This function is implemented in C. One of the first things this does is call compute_abstract_methods(self) checks all the abstract methods the class has inherited to see if they're implemented. This means getting Bar.x which invokes the property getter.

over 4 years ago · Santiago Trujillo Denunciar

0

This looks like a bug in the logic that checks for inherited abstract methods.

An object in a class dict is considered abstract if retrieving its __isabstractmethod__ attribute produces True. When Bar subclasses Foo, Python needs to determine whether Bar overrides the abstract Foo.x, and if so, whether the override is itself abstract. It should do this by searching the MRO for an 'x' entry in a class dict, so it can examine __isabstractmethod__ on descriptors directly without invoking the descriptor protocol, but instead, it performs a simple Bar.x attribute access.

The Bar.x attribute access invokes the class property. It also returns None instead of the abstract property, and None isn't abstract, so Python gets confused about whether Bar.x is abstract. Python ends up still thinking Bar.x is abstract due to a different check, but if you change the example a bit:

>>> from abc import ABC, abstractmethod
>>> 
>>> class Foo(ABC):
...     @classmethod
...     @property
...     @abstractmethod
...     def x(cls):
...         print(cls)
...         return None
... 
>>> class Bar(Foo): pass
... 
<class '__main__.Bar'>
>>> Bar()
<__main__.Bar object at 0x7f46eca8ab80>

Python ends up thinking Bar is a concrete class, even though the changed example doesn't override x at all.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda