Closest thing to a virtual call in python - python

Python does not provide some built-in inheritance mechanism to call implementations of base virtual or abstract methods in the derived class from the base methods
I am wondering what is the closest thing in python that would provide the following structure:
class Base(?):
def some_abstract_interface(self, **params):
raise Unimplemented()
def some_base_impl(self):
self.some_abstract_interface(self, a=4, b=3, c=2)
class Derived(Base):
#neat_override_decorator_here?
def some_abstract_interface(self, **params):
print("actual logic here {0}".format(params))
d = Derived()
d.some_base_impl()
>>>output: actual logic here a=4, b=3, c=2

You can already do that without any neat decorator:
class Base:
def some_abstract_interface(self):
raise NotImplemented
def some_base_impl(self):
self.some_abstract_interface()
class Derived(Base):
def some_abstract_interface(self):
print('actual logic here')
Derived().some_base_impl()
This outputs:
actual logic here
If you want to enforce that Base is an abstract class and cannot be used to instantiate an object directly, and that some_abstract_interface is meant to be an abstract method and always has to be overridden by an implementation of the method from a child class, you can make the base class inherit from the ABC class of the abc module and decorate abstract methods with abc.abstractmethod like this:
import abc
class Base(abc.ABC):
#abc.abstractmethod
def some_abstract_interface(self):
raise NotImplemented
def some_base_impl(self):
self.some_abstract_interface()
class Derived(Base):
def some_abstract_interface(self):
print('actual logic here')
Derived().some_base_impl()

You simply make the call yourself. That's not going to be any heavier, syntactically, then the decorator you posit.
class Derived(Base):
def some_abstract_interface(self, **params):
self.some_base_impl()
print('actual logic her {0}.format(params))
In fact, you don't even need to separate some_base_impl and some_abstract_interace; an abstract method can have an implementation but still require overriding.
from abc import ABC, abstractmethod
class Base(ABC):
#abstractmethod
def some_abstract_interface(self, **params):
pass # Put base implementation here
class Derived(Base):
def some_abstract_interface(self, **params):
super().some_abstract_interface(**params)
print("actual logic here {0}".format(params))

Related

How to typehint that an object of a class is also adhering to a Protocol in Python?

I have a set of classes, Lets call them Foo and Bar, where both inherit from a base class Father that is defined outside of the current scope (not by me). I have definied a protocol class DummyProtocol that has a function do_something.
class DummyProtocol(Protocol):
def do_something(self):
...
class Foo(Father):
def do_something(self):
pass
class Bar(Father):
def do_something(self):
pass
I have a function create_instance.
def create_dummy_and_father_instance(cls, *args, **kwargs):
return cls(*args, **kwargs)
I want to typehint it in a way, that cls is typehinted to accept a class that is of type Father that also implements the DummyProtocol.
So I changed the function to this to indicate that cls is a type that inherit from both Father and DummyProtocol
def create_dummy_and_father_instance(
cls: Type[tuple[Father, DummyProtocol]], *args, **kwargs
):
return cls(*args, **kwargs)
But I get this error in mypy:
Cannot instantiate type "Type[Tuple[Father, DummyProtocol]]"
I came across the same issue and found this discussion on proposed Intersection types which seem to be exactly what is needed (e.g. see this comment).
Unfortunately this feature is not yet supported by the Python typing system, but there's a PEP in the making.
You can define a second Father class which inherits from Father and Protocol (see also mypy: how to verify a type has multiple super classes):
class DummyProtocol(Protocol):
def do_something(self):
...
class Father:
pass
class Father2(Father, DummyProtocol):
pass
class Foo(Father2):
def do_something(self):
pass
class Bar(Father2):
def do_something(self):
pass
class FooNot(Father):
pass
def create_dummy_and_father_instance(
cls: Type[Father2]
):
return cls()
create_dummy_and_father_instance(Foo)
create_dummy_and_father_instance(Bar)
create_dummy_and_father_instance(FooNot) # mypy error ok

Proper way to implement ABC SubClass

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 :)

How to incorporate type checking in an abstract base class in Python

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.

Can I ensure that python base class method is always called

I have a python abstract base class as follows:
class Node(object):
"""
All concrete node classes should inherit from this
"""
__metaclass__ = ABCMeta
def __init__(self, name):
self.name = name
self.inputs = dict()
def add_input(self, key, value=None, d=None):
self.inputs[key] = (d, value)
def bind_input(self):
print "Binding inputs"
#abstractmethod
def run(self):
pass
Now, various derived classes will inherit from this node class and override the run method. It is always the case that bind_input() must be the first thing that should be called in the run method. Currently, for all derived classes the developer has to make sure to first call self.bind_input(). This is not a huge problem per se but out of curiosity is it possible to ensure this somehow from the base class itself that bind_input is called before executing the child object's run?
The usual object-oriented approach is this:
def run(self):
self.bind_input()
return self.do_run()
#abstractmethod
def do_run(self):
pass # override this method
Have your subclasses override the inner method, instead of the outer one.

Abstract base class is not enforcing function 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 :)

Categories

Resources