0

Consider the following code

from abc import ABC, ABCMeta


class MyMetaClass(ABCMeta):
    @property
    def metaclass_property(cls):
        return "result"

    # def __dir__(cls):
    #     return list(super().__dir__()) + ['metaclass_property']


class MyBaseClass(ABC, metaclass=MyMetaClass):
    @classmethod
    @property
    def baseclass_property(cls):
        return "result"


class MyClass(MyBaseClass, metaclass=MyMetaClass):
    pass


assert MyClass.baseclass_property == "result"
assert hasattr(MyClass, 'baseclass_property')
assert 'baseclass_property' in dir(MyClass)

assert MyClass.metaclass_property == "result"
assert hasattr(MyClass, 'metaclass_property')
assert 'metaclass_property' in dir(MyClass)

I noticed that this throws an assertion error on the last line. (python v3.9.6). Why is that? Is it a bug? It can be fixed by manually adding it to __dir__ as per the two uncommented lines.

My question is, what is the best way to resolve this? Is there any fundamental difference between a classmethod property or a metaclass property? (I.e. are there any things that I can or cannot do in one but not the other?) If not, which one should I preferably use?

Hyperplane
  • 1,422
  • 1
  • 14
  • 28

1 Answers1

1

I think this has nothing to do with properties, metaclasses or abc.

A simple example:

>>> int.__mro__
(<class 'int'>, <class 'object'>)
>>> isinstance(int, type)
True
>>> '__mro__' in dir(int)
False
>>> '__mro__' in dir(type)
True

In this example, object is the base class of int, while type is the metaclass of int.

The official documentation of the dir function explicitly says that it

attempts to produce the most relevant, rather than complete, information

and

If the object is a type or class object, the list contains the names of its attributes, and recursively of the attributes of its bases.

and

metaclass attributes are not in the result list when the argument is a class

mportes
  • 1,589
  • 5
  • 13