Suppose I define an abstract base class like this:
from abc import abstractmethod, ABCMeta class Quacker(object): __metaclass__ = ABCMeta @abstractmethod def quack(self): return "Quack!"
This ensures any class deriving from Quacker
must implement the quack
method. But if I define the following:
class PoliteDuck(Quacker): def quack(self, name): return "Quack quack %s!" % name d = PoliteDuck() # no error
I'm allowed to instantiate the class because I've provided the quack
method, but the function signatures don't match. I can see how this might be useful in some situations, but I'm in interested in ensuring I can definitely call the abstract methods. This might fail if the function signature is different!
So: how can I enforce a matching function signature? I would expect an error when creating the object if the signatures don't match, just like if I hadn't defined it at all.
I know that this is not idiomatic, and that Python is the wrong language to be using if I want these sorts of guarantees, but that's beside the point - is it possible?
A class is called an Abstract class if it contains one or more abstract methods. An abstract method is a method that is declared, but contains no implementation. Abstract classes may not be instantiated, and its abstract methods must be implemented by its subclasses.
Since Java 8, methods can be implemented ( can have a code body ) in an interface if only if it is declared static or default. Abstract methods cannot have a body; all they can have is a method signature as shown in the example above.
An abstract base class is a class that is used as a blueprint for other classes. Abstract base classes are a powerful feature in Python since they help you define a blueprint for other classes that may have something in common.
Python doesn't directly support abstract classes. But it does offer a module that allows you to define abstract classes. To define an abstract class, you use the abc (abstract base class) module. The abc module provides you with the infrastructure for defining abstract base classes.
It's worse than you think. Abstract methods are tracked by name only, so you don't even have to make quack
a method in order to instantiate the child class.
class SurrealDuck(Quacker): quack = 3 d = SurrealDuck() print d.quack # Shows 3
There is nothing in the system that enforces that quack
is even a callable object, let alone one whose arguments match the abstract method's original. At best, you could subclass ABCMeta
and add code yourself to compare type signatures in the child to the originals in the parent, but this would be nontrivial to implement.
(Currently, marking something as "abstract" essentially just adds the name to a frozen set attribute in the parent (Quacker.__abstractmethods__
). Making a class instantiable is as simple as setting this attribute to an empty iterable, which is useful for testing.)
I recommend you look at pylint. I ran this code through it's static analysis, and on the line where you defined the quack() method, it reported:
Argument number differs from overridden method (arguments-differ)
(https://en.wikipedia.org/wiki/Pylint)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With