Reputation: 378
I tried to make my realization where i don't need to use all times to all methods decorator @abstractmethod
Firstly, i realize class decorator, but this don't need any result:
from abc import ABC, abstractmethod
def interface(cls):
for attr in cls.__dict__:
if callable(getattr(cls, attr)):
setattr(cls, attr, abstractmethod(getattr(cls, attr)))
return cls
@interface
class A(ABC):
def foo(self):
pass
def bar(self):
pass
class B(A):
def foo(self):
pass
b = B()
Secondly, i tried make it in __init__
method in class and it's don't give any result too:
class Interface(ABC):
def __init__(self):
for attr in self.__dict__:
attr_obj = getattr(self, attr)
if callable(attr_obj):
setattr(self, attr, abstractmethod(attr_obj))
class A(Interface):
def __init__(self):
super().__init__()
def foo(self):
pass
def bar(self):
pass
class B(A):
def foo(self):
pass
b = B()
How can i realize a way where all methods in class decorated with @abstractmethod
?
Upvotes: 2
Views: 1057
Reputation: 106936
Like @juanpa.arrivillaga mentions, it's too late to decorate an abstract class after the class is instantiated since ABC
alters its class members with its metaclass, ABCMeta
.
Instead, you can subclass ABCMeta
(as Interface
in the example below) and perform modifications to the classdict
parameter of the class constructor before calling the constructor of the superclass.
Since child classes are supposed to implement abstract methods by default and not continue to declare methods abstract in typical cases, you should avoid decorating methods of child classes with abstractmethod
, but since child classes would inherit the metaclass of the parent, you would have to explicitly make the constructor of the Interface
return an object of ABCMeta
instead of Interface
itself so that the custom behavior would not be inherited:
from abc import ABCMeta, abstractmethod
class Interface(ABCMeta):
def __new__(metacls, name, bases, classdict):
for attr, value in classdict.items():
if callable(value):
classdict[attr] = abstractmethod(value)
return super().__new__(ABCMeta, name, bases, classdict)
so that:
class A(metaclass=Interface):
def foo(self):
pass
def bar(self):
pass
class B(A):
def foo(self):
pass
b = B()
would produce:
TypeError: Can't instantiate abstract class B with abstract method bar
while:
class A(metaclass=Interface):
def foo(self):
pass
def bar(self):
pass
class B(A):
def foo(self):
pass
def bar(self):
pass
would run with no error.
Upvotes: 1