__abstractmethods__ and AttributeError
Asked Answered
A

1

9

I was playing with the dir() builtin function when I noticed this:

>>> dir(type)
['__abstractmethods__', '__base__', '__bases__', '__basicsize__', '__call__', '__class__', '__delattr__', '__dict__', '__dictoffset__', '__dir__', '__doc__', '__eq__', '__flags__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__instancecheck__', '__itemsize__', '__le__', '__lt__', '__module__', '__mro__', '__name__', '__ne__', '__new__', '__prepare__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasscheck__', '__subclasses__', '__subclasshook__', '__text_signature__', '__weakrefoffset__', 'mro']
>>> type.__abstractmethods__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: __abstractmethods__
>>> list.__abstractmethods__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: __abstractmethods__

I don't understand, it appears in the list, why am I getting such error?

Anytime answered 23/7, 2014 at 15:24 Comment(0)
H
10

__abstractmethods__ is a descriptor to support Abstract Base Classes; it wraps a slot that is empty by default (so the descriptor raises an attribute error). Most of all, it is an implementation detail of how CPython handles abstract methods.

The attribute is used to track what methods are abstract, so that instances can be blocked from being created if they don't provide concrete implementations:

>>> import abc
>>> class FooABC(metaclass=abc.ABCMeta):
...     @abc.abstractmethod
...     def bar(self):
...         pass
... 
>>> FooABC.__abstractmethods__
frozenset({'bar'})
>>> class Foo(FooABC): pass
... 
>>> Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Foo with abstract methods bar

The abc.ABCMeta implementation sets the __abstractmethods__ attribute, and type() uses it to check for any abstract methods that should have been implemented but are not.

Holdup answered 23/7, 2014 at 15:26 Comment(3)
Wasn't it more consistent if __abstractmethods__ returned empty frozenset by default?Admetus
Why would an internal implementation detail have to do that? Why waste the memory on a frozenset() for something only a small number of classes use?Holdup
It might be more consistent if dir didn't return the name of something that would result in an AttributeError if accessed, but dir is documented as not necessarily being consistent.Perfoliate

© 2022 - 2024 — McMap. All rights reserved.