Say I have the following abstract class Foo:
import abc
class Foo(abc.ABC):
#abc.abstractmethod
def bar(self):
raise NotImplementedError
What should I put in the body of the bar method?
I see a lot of code that has raise NotImplementedError, as shown above. However, this seems redundant, since any subclass that does not implement bar will raise the TypeError: Can't instantiate abstract class Foo with abstract methods bar when it is instantiated.
Is it Pythonic to leave bar empty, as follows:
import abc
class Foo(abc.ABC):
#abc.abstractmethod
def bar(self):
...
This is what is done in the Python docs for Abstract Base Classes, but I'm not sure if that's just a placeholder or an actual example of how to write code.
If it's ok to leave bar with only three dots (...), when should I use NotImplementedError?
The documentation does aim to give you an example. You don't have to follow it.
You could provide a default; subclasses are still free to use super() to call your implementation. This is what most of the collections.abc classes do; see the source code.
Size for example, returns 0 for __len__:
class Sized(metaclass=ABCMeta):
# ...
#abstractmethod
def __len__(self):
return 0
As Martijn Pieters has said, provide a default in places where a default makes sense.
If you want to communicate to your user that they absolutely should override it, use raise NotImplementedError like so:
class FooBar(abc.ABC):
#abstractmethod
def foo(bar):
"""This method foos some bars"""
raise NotImplementedError
Quote:
exception NotImplementedError
This exception is derived from RuntimeError. In user defined base classes, abstract methods should raise this exception when they require derived classes to override the method, or while the class is being developed to indicate that the real implementation still needs to be added.
For completeness sake, here are some other things I have seen out in the wild (contradicting the official recommendation about raise NotImplementedError):
Instead of raising, just use Ellipses (...). this has some official support, since it is how the official python documentation for Abstract Base Classes uses it.
Just using pass is also quite common.
Actually, just using a docstring is sufficient. Imho any method should have a docstring anyways, so this would be more elegant than either ... or pass.
Related
Say I have the following abstract class Foo:
import abc
class Foo(abc.ABC):
#abc.abstractmethod
def bar(self):
raise NotImplementedError
What should I put in the body of the bar method?
I see a lot of code that has raise NotImplementedError, as shown above. However, this seems redundant, since any subclass that does not implement bar will raise the TypeError: Can't instantiate abstract class Foo with abstract methods bar when it is instantiated.
Is it Pythonic to leave bar empty, as follows:
import abc
class Foo(abc.ABC):
#abc.abstractmethod
def bar(self):
...
This is what is done in the Python docs for Abstract Base Classes, but I'm not sure if that's just a placeholder or an actual example of how to write code.
If it's ok to leave bar with only three dots (...), when should I use NotImplementedError?
The documentation does aim to give you an example. You don't have to follow it.
You could provide a default; subclasses are still free to use super() to call your implementation. This is what most of the collections.abc classes do; see the source code.
Size for example, returns 0 for __len__:
class Sized(metaclass=ABCMeta):
# ...
#abstractmethod
def __len__(self):
return 0
As Martijn Pieters has said, provide a default in places where a default makes sense.
If you want to communicate to your user that they absolutely should override it, use raise NotImplementedError like so:
class FooBar(abc.ABC):
#abstractmethod
def foo(bar):
"""This method foos some bars"""
raise NotImplementedError
Quote:
exception NotImplementedError
This exception is derived from RuntimeError. In user defined base classes, abstract methods should raise this exception when they require derived classes to override the method, or while the class is being developed to indicate that the real implementation still needs to be added.
For completeness sake, here are some other things I have seen out in the wild (contradicting the official recommendation about raise NotImplementedError):
Instead of raising, just use Ellipses (...). this has some official support, since it is how the official python documentation for Abstract Base Classes uses it.
Just using pass is also quite common.
Actually, just using a docstring is sufficient. Imho any method should have a docstring anyways, so this would be more elegant than either ... or pass.
Assume you're writing an abstract class and one or more of its non-abstract class methods require the concrete class to have a specific class attribute; e.g., if instances of each concrete class can be constructed by matching against a different regular expression, you might want to give your ABC the following:
#classmethod
def parse(cls, s):
m = re.fullmatch(cls.PATTERN, s)
if not m:
raise ValueError(s)
return cls(**m.groupdict())
(Maybe this could be better implemented with a custom metaclass, but try to ignore that for the sake of the example.)
Now, because overriding of abstract methods & properties is checked at instance creation time, not subclass creation time, trying to use abc.abstractmethod to ensure concrete classes have PATTERN attributes won't work — but surely there should be something there to tell anyone looking at your code "I didn't forget to define PATTERN on the ABC; the concrete classes are supposed to define their own." The question is: Which something is the most Pythonic?
Pile of decorators
#property
#abc.abstractmethod
def PATTERN(self):
pass
(Assume Python 3.4 or higher, by the way.) This can be very misleading to readers, as it implies that PATTERN should be an instance property instead of a class attribute.
Tower of decorators
#property
#classmethod
#abc.abstractmethod
def PATTERN(cls):
pass
This can be very confusing to readers, as #property and #classmethod normally can't be combined; they only work together here (for a given value of "work") because the method is ignored once it's overridden.
Dummy value
PATTERN = ''
If a concrete class fails to define its own PATTERN, parse will only accept empty input. This option isn't widely applicable, as not all use cases will have an appropriate dummy value.
Error-inducing dummy value
PATTERN = None
If a concrete class fails to define its own PATTERN, parse will raise an error, and the programmer gets what they deserve.
Do nothing. Basically a more hardcore variant of #4. There can be a note in the ABC's docstring somewhere, but the ABC itself shouldn't have anything in the way of a PATTERN attribute.
Other???
You can use the __init_subclass__ method which was introduced in Python 3.6 to make customizing class creation easier without resorting to metaclasses. When defining a new class, it is called as the last step before the class object is created.
In my opinion, the most pythonic way to use this would be to make a class decorator that accepts the attributes to make abstract, thus making it explicit to the user what they need to define.
from custom_decorators import abstract_class_attributes
#abstract_class_attributes('PATTERN')
class PatternDefiningBase:
pass
class LegalPatternChild(PatternDefiningBase):
PATTERN = r'foo\s+bar'
class IllegalPatternChild(PatternDefiningBase):
pass
The traceback might be as follows, and occurs at subclass creation time, not instantiation time.
NotImplementedError Traceback (most recent call last)
...
18 PATTERN = r'foo\s+bar'
19
---> 20 class IllegalPatternChild(PatternDefiningBase):
21 pass
...
<ipython-input-11-44089d753ec1> in __init_subclass__(cls, **kwargs)
9 if cls.PATTERN is NotImplemented:
10 # Choose your favorite exception.
---> 11 raise NotImplementedError('You forgot to define PATTERN!!!')
12
13 #classmethod
NotImplementedError: You forgot to define PATTERN!!!
Before showing how the decorator is implemented, it is instructive to show how you could implement this without the decorator. The nice thing here is that if needed you could make your base class an abstract base class without having to do any work (just inherit from abc.ABC or make the metaclass abc.ABCMeta).
class PatternDefiningBase:
# Dear programmer: implement this in a subclass OR YOU'LL BE SORRY!
PATTERN = NotImplemented
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
# If the new class did not redefine PATTERN, fail *hard*.
if cls.PATTERN is NotImplemented:
# Choose your favorite exception.
raise NotImplementedError('You forgot to define PATTERN!!!')
#classmethod
def sample(cls):
print(cls.PATTERN)
class LegalPatternChild(PatternDefiningBase):
PATTERN = r'foo\s+bar'
Here is how the decorator could be implemented.
# custom_decorators.py
def abstract_class_attributes(*names):
"""Class decorator to add one or more abstract attribute."""
def _func(cls, *names):
""" Function that extends the __init_subclass__ method of a class."""
# Add each attribute to the class with the value of NotImplemented
for name in names:
setattr(cls, name, NotImplemented)
# Save the original __init_subclass__ implementation, then wrap
# it with our new implementation.
orig_init_subclass = cls.__init_subclass__
def new_init_subclass(cls, **kwargs):
"""
New definition of __init_subclass__ that checks that
attributes are implemented.
"""
# The default implementation of __init_subclass__ takes no
# positional arguments, but a custom implementation does.
# If the user has not reimplemented __init_subclass__ then
# the first signature will fail and we try the second.
try:
orig_init_subclass(cls, **kwargs)
except TypeError:
orig_init_subclass(**kwargs)
# Check that each attribute is defined.
for name in names:
if getattr(cls, name, NotImplemented) is NotImplemented:
raise NotImplementedError(f'You forgot to define {name}!!!')
# Bind this new function to the __init_subclass__.
# For reasons beyond the scope here, it we must manually
# declare it as a classmethod because it is not done automatically
# as it would be if declared in the standard way.
cls.__init_subclass__ = classmethod(new_init_subclass)
return cls
return lambda cls: _func(cls, *names)
I've been searching for something like this for quite a while, until yesterday I decided to dive into it. I like #SethMMorton's reply a lot, however 2 things are missing: allow a an abstract class to have a subclass that is abstract itself, and play nice with typehints and static typing tools such as mypy (which makes sense, since back in 2017 these were hardly a thing).
I started to set out to write a reply here with my own solution, however I realised I needed lots of tests and documentation, so I made it a proper python module: abstractcp.
Use (as of version 0.9.5):
class Parser(acp.Abstract):
PATTERN: str = acp.abstract_class_property(str)
#classmethod
def parse(cls, s):
m = re.fullmatch(cls.PATTERN, s)
if not m:
raise ValueError(s)
return cls(**m.groupdict())
class FooBarParser(Parser):
PATTERN = r"foo\s+bar"
def __init__(...): ...
class SpamParser(Parser):
PATTERN = r"(spam)+eggs"
def __init__(...): ...
See for full use the page on pypi or github.
Alternative Answer
Using dedicated class to annotate class variables
import abc
from typing import Generic, Set, TypeVar, get_type_hints
T = TypeVar('T')
class AbstractClassVar(Generic[T]):
pass
class Abstract(abc.ABC):
def __init_subclass__(cls) -> None:
def get_abstract_members(cls) -> Set[str]:
"""Gets a class's abstract members"""
abstract_members = set()
if cls is Abstract:
return abstract_members
for base_cls in cls.__bases__:
abstract_members.update(get_abstract_members(base_cls))
for (member_name, annotation) in get_type_hints(cls).items():
if getattr(annotation, '__origin__', None) is AbstractClassVar:
abstract_members.add(member_name)
return abstract_members
# Implementation checking for abstract class members
if Abstract not in cls.__bases__:
for cls_member in get_abstract_members(cls):
if not hasattr(cls, cls_member):
raise NotImplementedError(f"Wrong class implementation {cls.__name__} " +
f"with abstract class variable {cls_member}")
return super().__init_subclass__()
Usage
class Foo(Abstract):
foo_member: AbstractClassVar[str]
class UpperFoo(Foo):
# Everything should be implemented as intended or else...
...
Not Implementing the abstract class member foo_member will result in a NotImplementedError.
Answer was taken from my original answer to this question: enforcement for abstract properties in python3
In Java, for example, you can make a class MyClass with certain methods that are specified but not implemented in MyClass, but must be implemented in any class MySubClass that inherits from MyClass. So basically there is some common functionality among all subclasses you want, so you put it in MyClass, and there is some functionality unique (but required) for each subclass, so you want it in each subclass. How can this behavior be achieved in Python?
(I know there are concise terms to describe what I'm asking, so feel free to let me know what these are and how I can better describe my question.)
A very basic example but the abc docs provide a few more
import abc
class Foo():
__metaclass__ = abc.ABCMeta
#abc.abstractmethod
def bar(self):
raise NotImplemented
class FooBar(Foo):
pass
f = FooBar()
TypeError: Can't instantiate abstract class FooBar with abstract methods bar
You can't require the implementation of a method in a subclass in a way that will break at compile-time, but the convention on writing a method on the base class that must be implemented in the subclasses is to raise NotImplementedError.
Something like this:
class MyBase(object):
def my_method(self, *args, **kwargs):
raise NotImplementedError("You should implement this method on a subclass of MyBase")
Then your subclasses can implement my_method, but this will break only when the method is called. If you have comprehensive unit tests, as you should, this won't be a problem.
It seems that checking isinstance(..., io.IOBase) is the 'correct' way to determine if an object is 'file-like'.
However, when defining my own file-like class, it doesn't seem to work:
import io
class file_like():
def __init__(self):
pass
def write(self, line):
print("Written:", line)
def close(self):
pass
def flush(self):
pass
print(isinstance(file_like(), io.IOBase))
# Prints 'False'
How can I make it work?
isinstance(obj, some_class) just iterates up obj's inheritance chain, looking for some_class. Thus isinstance(file_like, io.IOBase), will be false, as your file_like class doesn't have io.IOBase in its ancestry. file_like doesn't designate an explicit parent, hence it implicitly inherits only from object. That's the only class - besides file_like itself - that will test positive for a file_like instance with isinstance().
What you are doing in file_like is defining the methods expected on a file-like object while not inheriting from any particular "file-like" class. This approach is called duck-typing, and it has many merits in dynamic languages, although it's more popular in others (e.g. Ruby) than Python. Still, if whatever you're providing your file_like instance to follows duck-typing, it should work, provided your file_like does in fact "quack like a file", i.e. behaves sufficiently like a file to not cause errors upon usage at the receiving end.
Of course, if the receiving end is not following duck-typing, for example tries to check types by isinstance() as you do here, this approach will fail.
Finally, a small stylistic nit: don't put empty parens on a class if it doesn't inherit anything explicitly. They are redundant.
Checking isinstance(something, io.IOBase) only checks if something is an instance of an io.IOBase or a class derived from it — so I don't understand where you got the mistaken idea that it's the "correct" way to determine if an object is "file-like".
A different way to do it is with an Abstract Base Class. Python has a number of built-in ones, but currently doesn't have one for "file-like" that could used with isinstance(). However you can define your own by using the abc module as outlined in PEP 3119.
The Python Module of the Week webiste has a good explanation of using the abc module to do things like as this. And this highly rated answer to the question Correct way to detect sequence parameter? shows a similar way of defining your own ABC.
To illustrate applying it to your case, you could define an ABC like this with all its methods abstract — thereby forcing derived classes to define all of them in order to be instantiated:
from abc import ABCMeta, abstractmethod
class ABCFileLike(metaclass=ABCMeta):
#abstractmethod
def __init__(self): pass
#abstractmethod
def write(self, line): pass
#abstractmethod
def close(self): pass
#abstractmethod
def flush(self): pass
You could then derive your own concrete classes from it, making sure to supply implementations of all the abstract methods. (If you don't define them all, then a TypeError will be be raised if any attempts are made to instantiate it.)
class FileLike(ABCFileLike):
""" Concrete implementation of a file-like class.
(Meaning all the abstract methods have an implementation.)
"""
def __init__(self):
pass
def write(self, line):
print("Written:", line)
def close(self):
pass
def flush(self):
pass
print(isinstance(FileLike(), ABCFileLike)) # -> True
You can even add existing classes to it by registering them with the new metaclass:
import io
print(isinstance(io.IOBase(), ABCFileLike)) # -> False
ABCFileLike.register(io.IOBase)
print(isinstance(io.IOBase(), ABCFileLike)) # -> True
Because I am used to the old ways of duck typing in Python, I fail to understand the need for ABC (abstract base classes). The help is good on how to use them.
I tried to read the rationale in the PEP, but it went over my head. If I was looking for a mutable sequence container, I would check for __setitem__, or more likely try to use it (EAFP). I haven't come across a real life use for the numbers module, which does use ABCs, but that is the closest I have to understanding.
Can anyone explain the rationale to me, please?
#Oddthinking's answer is not wrong, but I think it misses the real, practical reason Python has ABCs in a world of duck-typing.
Abstract methods are neat, but in my opinion they don't really fill any use-cases not already covered by duck typing. Abstract base classes' real power lies in the way they allow you to customise the behaviour of isinstance and issubclass. (__subclasshook__ is basically a friendlier API on top of Python's __instancecheck__ and __subclasscheck__ hooks.) Adapting built-in constructs to work on custom types is very much part of Python's philosophy.
Python's source code is exemplary. Here is how collections.Container is defined in the standard library (at time of writing):
class Container(metaclass=ABCMeta):
__slots__ = ()
#abstractmethod
def __contains__(self, x):
return False
#classmethod
def __subclasshook__(cls, C):
if cls is Container:
if any("__contains__" in B.__dict__ for B in C.__mro__):
return True
return NotImplemented
This definition of __subclasshook__ says that any class with a __contains__ attribute is considered to be a subclass of Container, even if it doesn't subclass it directly. So I can write this:
class ContainAllTheThings(object):
def __contains__(self, item):
return True
>>> issubclass(ContainAllTheThings, collections.Container)
True
>>> isinstance(ContainAllTheThings(), collections.Container)
True
In other words, if you implement the right interface, you're a subclass! ABCs provide a formal way to define interfaces in Python, while staying true to the spirit of duck-typing. Besides, this works in a way that honours the Open-Closed Principle.
Python's object model looks superficially similar to that of a more "traditional" OO system (by which I mean Java*) - we got yer classes, yer objects, yer methods - but when you scratch the surface you'll find something far richer and more flexible. Likewise, Python's notion of abstract base classes may be recognisable to a Java developer, but in practice they are intended for a very different purpose.
I sometimes find myself writing polymorphic functions that can act on a single item or a collection of items, and I find isinstance(x, collections.Iterable) to be much more readable than hasattr(x, '__iter__') or an equivalent try...except block. (If you didn't know Python, which of those three would make the intention of the code clearest?)
That said, I find that I rarely need to write my own ABC and I typically discover the need for one through refactoring. If I see a polymorphic function making a lot of attribute checks, or lots of functions making the same attribute checks, that smell suggests the existence of an ABC waiting to be extracted.
*without getting into the debate over whether Java is a "traditional" OO system...
Addendum: Even though an abstract base class can override the behaviour of isinstance and issubclass, it still doesn't enter the MRO of the virtual subclass. This is a potential pitfall for clients: not every object for which isinstance(x, MyABC) == True has the methods defined on MyABC.
class MyABC(metaclass=abc.ABCMeta):
def abc_method(self):
pass
#classmethod
def __subclasshook__(cls, C):
return True
class C(object):
pass
# typical client code
c = C()
if isinstance(c, MyABC): # will be true
c.abc_method() # raises AttributeError
Unfortunately this one of those "just don't do that" traps (of which Python has relatively few!): avoid defining ABCs with both a __subclasshook__ and non-abstract methods. Moreover, you should make your definition of __subclasshook__ consistent with the set of abstract methods your ABC defines.
Short version
ABCs offer a higher level of semantic contract between clients and the implemented classes.
Long version
There is a contract between a class and its callers. The class promises to do certain things and have certain properties.
There are different levels to the contract.
At a very low level, the contract might include the name of a method or its number of parameters.
In a staticly-typed language, that contract would actually be enforced by the compiler. In Python, you can use EAFP or type introspection to confirm that the unknown object meets this expected contract.
But there are also higher-level, semantic promises in the contract.
For example, if there is a __str__() method, it is expected to return a string representation of the object. It could delete all contents of the object, commit the transaction and spit a blank page out of the printer... but there is a common understanding of what it should do, described in the Python manual.
That's a special case, where the semantic contract is described in the manual. What should the print() method do? Should it write the object to a printer or a line to the screen, or something else? It depends - you need to read the comments to understand the full contract here. A piece of client code that simply checks that the print() method exists has confirmed part of the contract - that a method call can be made, but not that there is agreement on the higher level semantics of the call.
Defining an Abstract Base Class (ABC) is a way of producing a contract between the class implementers and the callers. It isn't just a list of method names, but a shared understanding of what those methods should do. If you inherit from this ABC, you are promising to follow all the rules described in the comments, including the semantics of the print() method.
Python's duck-typing has many advantages in flexibility over static-typing, but it doesn't solve all the problems. ABCs offer an intermediate solution between the free-form of Python and the bondage-and-discipline of a staticly-typed language.
A handy feature of ABCs is that if you don't implement all necessary methods (and properties) you get an error upon instantiation, rather than an AttributeError, potentially much later, when you actually try to use the missing method.
from abc import ABCMeta, abstractmethod
# python2
class Base(object):
__metaclass__ = ABCMeta
#abstractmethod
def foo(self):
pass
#abstractmethod
def bar(self):
pass
# python3
class Base(object, metaclass=ABCMeta):
#abstractmethod
def foo(self):
pass
#abstractmethod
def bar(self):
pass
class Concrete(Base):
def foo(self):
pass
# We forget to declare `bar`
c = Concrete()
# TypeError: "Can't instantiate abstract class Concrete with abstract methods bar"
Example from https://dbader.org/blog/abstract-base-classes-in-python
Edit: to include python3 syntax, thanks #PandasRocks
It will make determining whether an object supports a given protocol without having to check for presence of all the methods in the protocol or without triggering an exception deep in "enemy" territory due to non-support much easier.
Abstract method make sure that what ever method you are calling in the parent class has to be appear in child class. Below are noraml way of calling and using abstract.
The program written in python3
Normal way of calling
class Parent:
def methodone(self):
raise NotImplemented()
def methodtwo(self):
raise NotImplementedError()
class Son(Parent):
def methodone(self):
return 'methodone() is called'
c = Son()
c.methodone()
'methodone() is called'
c.methodtwo()
NotImplementedError
With Abstract method
from abc import ABCMeta, abstractmethod
class Parent(metaclass=ABCMeta):
#abstractmethod
def methodone(self):
raise NotImplementedError()
#abstractmethod
def methodtwo(self):
raise NotImplementedError()
class Son(Parent):
def methodone(self):
return 'methodone() is called'
c = Son()
TypeError: Can't instantiate abstract class Son with abstract methods methodtwo.
Since methodtwo is not called in child class we got error. The proper implementation is below
from abc import ABCMeta, abstractmethod
class Parent(metaclass=ABCMeta):
#abstractmethod
def methodone(self):
raise NotImplementedError()
#abstractmethod
def methodtwo(self):
raise NotImplementedError()
class Son(Parent):
def methodone(self):
return 'methodone() is called'
def methodtwo(self):
return 'methodtwo() is called'
c = Son()
c.methodone()
'methodone() is called'
ABC's enable design patterns and frameworks to be created. Please see this pycon talk by Brandon Rhodes:
Python Design Patterns 1
The protocols within Python itself (not to mention iterators, decorators, and slots (which themselves implement the FlyWeight pattern)) are all possible because of ABC's (albeit implemented as virtual methods/classes in CPython).
Duck typing does make some patterns trivial in python, which Brandon mentions, but many other patterns continue to pop up and be useful in Python, e.g. Adapters.
In short, ABC's enable you to write scalable and reusable code. Per the GoF:
Program to an interface, not an implementation (inheritance breaks encapsulation; programming to an interface promotes loose-coupling/inversion of control/the "HollyWood Principle: Don't call us, we'll call you")
Favor object composition over class inheritance (delegate the work)
Encapsulate the concept that varies (the open-closed principle makes classes open for extension, but closed for modification)
Additionally, with the emergence of static type checkers for Python (e.g. mypy), an ABC can be used as a type instead of Union[...] for every object a function accepts as an argument or returns. Imagine having to update the types, not the implementation, every time your code base supports a new object? That gets unmaintainable (doesn't scale) very fast.