Home > Article > Backend Development > Defining and using abstract classes in Python
Everyone is familiar with abstract classes in Java. In Python, we can use the abc module to build abstract classes. Here we will explain how to define and use abstract classes in Python
Like java, python You can also define an abstract class.
Before talking about abstract classes, let’s talk about the implementation of abstract methods.
Abstract methods are methods defined in the base class, but do not have any implementation. In java, you can declare a method as an interface. The simple way to implement an abstract method in python is:
class Sheep(object): def get_size(self): raise NotImplementedError
Any subclass inherited from Sheep must implement the get_size method. Otherwise an error will be generated. But this implementation method has a drawback. The defined subclass will only throw an error when that method is called. Here's a simple way to trigger it after the class is instantiated. Use the abc module provided by python.
import abc class Sheep(object): __metaclass__ = abc.ABCMeta @abc.absractmethod def get_size(self): return
An exception will be thrown when instantiating the Sheep class or any subclass inherited from it (get_size is not implemented).
Therefore, by defining an abstract class, you can define a common method for subclasses (forcing its implementation).
How to use abstract classes
import abc class A(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def load(self, input): return @abc.abstractmethod def save(self, output, data): return
To create an abstract class through the ABCMeta metaclass, use the abstractmethod decorator. Indicate abstract method
Register a concrete class
class B(object): def load(self, input): return input.read() def save(self, output, data): return output.write(data) A.register(B) if __name__ == '__main__': print issubclass(B, A) # print True print isinstance(B(), A) # print True
Register a concrete class from an abstract class
Subclassing implementation
class C(A): def load(self, input): return input.read() def save(self, output, data): return output.write(data) if __name__ == '__main__': print issubclass(C, A) # print True print isinstance(C(), A) # print True
You can use the method of inheriting abstract classes to implement concrete classes, which can avoid using register. But the side effects are You can find all concrete classes through the base class
for sc in A.__subclasses__(): print sc.__name__ # print C
If you use inheritance, you will find all concrete classes, but if you use register, you will not. Found out
Use __subclasshook__
After using __subclasshook__, as long as the concrete class defines the same method as the abstract class, it is considered to be his subclass
import abc class A(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def say(self): return 'say yeah' @classmethod def __subclasshook__(cls, C): if cls is A: if any("say" in B.__dict__ for B in C.__mro__): return True return NotTmplementd class B(object): def say(self): return 'hello' print issubclass(B, A) # True print isinstance(B(), A) # True print B.__dict__ # {'say': <function say at 0x7f...>, ...} print A.__subclasshook__(B) # True
Incomplete implementation
class D(A): def save(self, output, data): return output.write(data) if __name__ == '__main__': print issubclass(D, A) # print True print isinstance(D(), A) # raise TypeError
D will be thrown if an incomplete concrete class is built Abstract classes and abstract methods cannot be instantiated
Use abstract base classes in concrete classes
import abc from cStringIO import StringIO class A(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def retrieve_values(self, input): pirnt 'base class reading data' return input.read() class B(A): def retrieve_values(self, input): base_data = super(B, self).retrieve_values(input) print 'subclass sorting data' response = sorted(base_data.splitlines()) return response input = StringIO("""line one line two line three """) reader = B() print reader.retrieve_values(input)
Print results
base class reading data subclass sorting data ['line one', 'line two', 'line three']
You can use super to reuse logic in abstract base classes, but it will force subclasses to provide override methods.
Abstract attributes
import abc class A(object): __metaclass__ = abc.ABCMeta @abc.abstractproperty def value(self): return 'should never get here.' class B(A): @property def value(self): return 'concrete property.' try: a = A() print 'A.value', a.value except Exception, err: print 'Error: ', str(err) b = B() print 'B.value', b.value
Print result, A cannot be instantiated because there is only one abstract property getter method.
Error: ... print concrete property
Define abstract read-write properties
import abc class A(object): __metaclass__ = abc.ABCMeta def value_getter(self): return 'Should never see this.' def value_setter(self, value): return value = abc.abstractproperty(value_getter, value_setter) class B(A): @abc.abstractproperty def value(self): return 'read-only' class C(A): _value = 'default value' def value_getter(self): return self._value def value_setter(self, value): self._value = value value = property(value_getter, value_setter) try: a = A() print a.value except Exception, err: print str(err) try: b = B() print b.value except Exception, err: print str(err) c = C() print c.value c.value = 'hello' print c.value
Print results, must be defined when defining the property of a specific class Same as abstract abstract property. If you only override one of them it will not work.
error: ... error: ... print 'default value' print 'hello'
Use decorator syntax to implement abstract properties for reading and writing. The methods for reading and writing should be the same.
import abc class A(object): __metaclass__ = abc.ABCMeta @abc.abstractproperty def value(self): return 'should never see this.' @value.setter def value(self, _value): return class B(A): _value = 'default' @property def value(self): return self._value @value.setter def value(self, _value): self._value = _value b = B() print b.value # print 'default' b.value = 'hello' print b.value # print 'hello'
For more articles related to defining and using abstract classes in Python, please pay attention to the PHP Chinese website!