I have one base class with abstractmethod and subclass which implements this method. How to determine in runtime if in object (without checking type of object or calling method) that method is abstract or not?
class Base:
#abc.abstractmethod
def someAbstractMethod(self):
raise NotImplementedError("Not implemented yet.")
class Subclass(Base):
def someAbstractMethod(self):
some_operations
objects = [Base(),Subclass(),Base(),Subclass(),Subclass(),...]
for object in objects:
#here I want check if method is still abstract or not
Python prevents the creation of instances for classes with abstract methods. So just the fact that you have an instance means you have no abstract methods.
You do, however, have to use the ABCMeta metaclass to properly trigger this behaviour:
class Base(metaclass=abc.ABCMeta):
#abc.abstractmethod
def someAbstractMethod(self):
raise NotImplementedError("Not implemented yet.")
You can also inherit from abc.ABC to get the same metaclass via a base class.
If you wanted to see what abstract methods a class might have listed, use the __abstractmethods__ attribute; it is a set of all names that are still abstract:
>>> import abc
>>> class Base(metaclass=abc.ABCMeta):
... #abc.abstractmethod
... def someAbstractMethod(self):
... raise NotImplementedError("Not implemented yet.")
...
>>> class Subclass(Base):
... def someAbstractMethod(self):
... some_operations
...
>>> Base.__abstractmethods__
frozenset({'someAbstractMethod'})
>>> Subclass.__abstractmethods__
frozenset()
All that the #abc.abstractmethod decorator does is set a __isabstractmethod__ attribute on the function object; it is the metaclass that then uses those attributes.
So if you are dig in too deep or are using a third-party library that has forgotten to use the ABCMeta metaclass, you can test for those attributes:
>>> class Base: # note, no metaclass!
... #abc.abstractmethod
... def someAbstractMethod(self):
... raise NotImplementedError("Not implemented yet.")
...
>>> getattr(Base().someAbstractMethod, '__isabstractmethod__', False)
True
If you need to 'repair' such broken abstract base classes, you'd need subclass and mix in ABCMeta, and add a __abstractmethods__ frozenset to the class you are inheriting from:
BaseClass.__abstractmethods__ = frozenset(
name for name, attr in vars(BaseClass).items()
if getattr(attr, '__isabstractmethod__', False))
class DerivedClass(BaseClass, metaclass=abc.ABCMeta):
# ...
Now DerivedClass is a proper ABC-derived class where any abstract methods are properly tracked and acted on.
You're not using abc correctly here (well not as it's intended to be used at least). Your Base class should use abc.ABCMeta as metaclass, which would prevent instanciation of child classes not implementing abstractmethods. Else just using the abc.abstractmethod decorator is mostly useless.
Python 2.7:
class Base(object):
__metaclass__ = abc.ABCMeta
#abc.abstractmethod
def someAbstractMethod(self):
# no need to raise an exception here
pass
Python 3.x
class Base(metaclass=abc.ABCMeta):
#abc.abstractmethod
def someAbstractMethod(self):
# no need to raise an exception here
pass
Related
I have an Interface class which defines the requirements to an active "in-use" class:
class Portfolio(ABC):
#abstractmethod
def update_portfolio(self):
raise NotImplementedError
#abstractmethod
def update_from_fill(self):
raise NotImplementedError
#abstractmethod
def check_signal(self, signal_event):
raise NotImplementedError
The methods update_portfolio and update_from_fill are both methods which will be the same in 99% of the required cases. Only the check_signal method will vary. Therefore, to avoid having to write the same code again and again, I have defined a base class with default methods for update_portfolio and update_from_fill:
class BaseBacktestPortfolio(Portfolio):
def __init__(self, ...):
...
def update_portfolio(self, ...):
...
def update_from_fill(self, ...):
...
Then, finally, I have a class inheriting from the BacktestPortfolio class which specifies the correct implementation of the check_signal method:
class USBacktestPortfolio(BaseBacktestPortfolio):
def check_signal(self, ...):
...
Now, the problem is that my editor complains about the BacktestPortfolio classing not having all the required abstract methods. I could ignore this, of course, but the perfect scenario would be if I could make sure that it is not possible to instantiate an object form the BacktestPortfolio class.
Is this possible? And/or is there a more correct way to implement a structure like this?
I could ignore this, of course, but the perfect scenario would be if I could make sure that it is not possible to instantiate an object from the BacktestPortfolio class.
That is the case in your example already:
>>> BaseBacktestPortfolio.mro()
[__main__.BaseBacktestPortfolio, __main__.Portfolio, abc.ABC, object]
>>> BaseBacktestPortfolio()
TypeError: Can't instantiate abstract class BaseBacktestPortfolio with abstract methods check_signal
Since ABC and ABCMeta are just regular types, their features are inherited. This includes their guards against instantiating incomplete classes. Your BaseBacktestPortfolio already is an abstract class.
The warning from your IDE/linter/... exists specifically to warn you that instantiating BaseBacktestPortfolio is not possible.
You can make the BaseBacktestPortfolio also as Abstract class.
from abc import ABC, abstractmethod
class Portfolio(ABC):
#abstractmethod
def update_portfolio(self):
pass
#abstractmethod
def update_from_fill(self):
pass
#abstractmethod
def check_signal(self, signal_event):
pass
class BaseBacktestPortfolio(Portfolio, ABC):
def update_portfolio(self):
print("updated portfolio")
def update_from_fill(self):
print("update from fill")
#abstractmethod
def check_signal(self):
pass
class USBacktestPortfolio(BaseBacktestPortfolio):
def check_signal(self):
print("checked signal")
Also notice that you don't need raise NotImplementedError inside abstract method. You can just pass. Its more Pythonic :)
In python, can I define an interface (abstract class) by inheritance from another abstract class?
If I try:
import abc
ABC = abc.ABCMeta('ABC', (object,), {})
class interface(ABC):
#abc.abstractmethod
def method(self, message):
return
class InterfaceExtended(ABC, interface):
#abc.abstractmethod
def NewMethod(self, message):
return
I get an error on the "InterfaceExtended" class :
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases ABC, Interface
Don't inherit from ABC in your second class. The interface it derives from already inherits ABC
When I define a class, I like to include type checking (using assert) of the input variables. I am now defining a 'specialized' class Rule which inherits from an abstract base class (ABC) BaseRule, similar to the following:
import abc
class BaseRule(object):
__metaclass__ = abc.ABCMeta
#abc.abstractproperty
def resources(self):
pass
class Rule(BaseRule):
def __init__(self, resources):
assert all(isinstance(resource, Resource) for resource in resources) # type checking
self._resources = resources
#property
def resources(self):
return self._resources
class Resource(object):
def __init__(self, domain):
self.domain = domain
if __name__ == "__main__":
resources = [Resource("facebook.com")]
rule = Rule(resources)
The assert statement in the __init__ function of the Rule class ensures that the resources input is a list (or other iterable) of Resource objects. However, this would also be the case for other classes which inherit from BaseRule, so I would like to incorporate this assertion in the abstractproperty somehow. How might I go about this?
See this documentation on abc Type annotations with mypy-lang https://mypy.readthedocs.io/en/latest/class_basics.html#abstract-base-classes-and-multiple-inheritance
Make your base class have a non-abstract property that calls separate abstract getter and setter methods. The property can do the validation you want before calling the setter. Other code (such as the __init__ method of a derived class) that wants to trigger the validation can do so by doing its assignment via the property:
class BaseRule(object):
__metaclass__ = abc.ABCMeta
#property
def resources(self): # this property isn't abstract and shouldn't be overridden
return self._get_resources()
#resources.setter
def resources(self, value):
assert all(isinstance(resource, Resources) for resource in value)
self._set_resources(value)
#abstractmethod
def _get_resources(self): # these methods should be, instead
pass
#abstractmethod
def _set_resources(self, value):
pass
class Rule(BaseRule):
def __init__(self, resources):
self.resources = resources # assign via the property to get type-checking!
def _get_resources(self):
return self._resources
def _set_resources(self, value):
self._resources = value
You might even consider moving the __init__ method from Rule into the BaseRule class, since it doesn't need any knowledge about Rule's concrete implementation.
from abc import abstractmethod, ABCMeta
class AbstractBase(object):
__metaclass__ = ABCMeta
#abstractmethod
def must_implement_this_method(self):
raise NotImplementedError()
class ConcreteClass(AbstractBase):
def extra_function(self):
print('hello')
# def must_implement_this_method(self):
# print("Concrete implementation")
d = ConcreteClass() # no error
d.extra_function()
I'm on Python 3.4. I want to define an abstract base class that defines somes functions that need to be implemented by it's subclassses. But Python doesn't raise a NotImplementedError when the subclass does not implement the function...
The syntax for the declaration of metaclasses has changed in Python 3. Instead of the __metaclass__ field, Python 3 uses a keyword argument in the base-class list:
import abc
class AbstractBase(metaclass=abc.ABCMeta):
#abc.abstractmethod
def must_implement_this_method(self):
raise NotImplementedError()
Calling d = ConcreteClass() will raise an exception now, because a metaclass derived from ABCMeta can not be instantiated unless all of its abstract methods and properties are overridden (For more information see #abc.abstractmethod):
TypeError: Can't instantiate abstract class ConcreteClass with abstract methods
must_implement_this_method
Hope this helps :)
So I have a .py file containing a class where its subclasses can be accessed as properties. All these subclasses are defined beforehand. I also need all the subclasses to have the same ability (having their own subclasses be accessible as properties). The biggest problem I've been facing is that I don't know how to access the current class within my implementation of __getattr__(), so that'd be a good place to start.
Here's some Python+Pseudocode with what I've tried so far. I'm pretty sure it won't work since __getattr__() seems to be only working with instances of a class. If that is case, sorry, I am not as familiar with OOP in Python as I would like.
class A(object):
def __getattr__(self, name):
subclasses = [c.__name__ for c in current_class.__subclasses__()]
if name in subclasses:
return name
raise AttributeError
If I've understood your question properly, you can do what you want by using a custom metaclass that adds a classmethod to its instances. Here's an example:
class SubclassAttributes(type):
def __getattr__(cls, name): # classmethod of instances
for subclass in cls.__subclasses__():
if subclass.__name__ == name:
return subclass
else:
raise TypeError('Class {!r} has no subclass '
'named {!r}'.format(cls.__name__, name))
class Base(object):
__metaclass__ = SubclassAttributes # Python 2 metaclass syntax
#class Base(object, metaclass=SubclassAttributes): # Python 3 metaclass syntax
# """ nothing to see here """
class Derived1(Base): pass
class Derived2(Base): pass
print(Base.Derived1) # -> <class '__main__.Derived1'>
print(Base.Derived2) # -> <class '__main__.Derived2'>
print(Base.Derived3) # -> TypeError: Class 'Base' has no subclass named 'Derived3'
For something that works in both Python 2 and 3, define the class as shown below. Derives Base from a class that has SubclassAttributes as its metaclass. The is similar to what the six module's with_metaclass() function does:
class Base(type.__new__(type('TemporaryMeta', (SubclassAttributes,), {}),
'TemporaryClass', (), {})): pass
class A(object):
def __getattr__(self, key):
for subclass in self.__class__.__subclasses__():
if (subclass.__name__ == key):
return subclass
raise AttributeError, key
Out of curiosity, what is this designed to be used for?
>>> class A(object):
... pass
...
>>> foo = A()
>>> foo.__class__
<class '__main__.A'>