How to program based on interfaces in Python

It takes about 2 minutes to read this article.

In the software industry, the only constant is change. Product managers will change, product requirements will change, and code will also change. Different code designs and changes bring about different workloads. Some changes require almost a refactoring, while some only need to modify a configuration file or add a line of code to the class. Of course, a better code design is easy to maintain because it has good scalability, high cohesion, and low coupling. If you want a good code design, we need to learn design patterns. Today I will share with you how to program based on interfaces in Python.

1994 There is an important principle in GoF's "Design Patterns" book in 2015: based on interfaces rather than implementation programming. The original English text is "Program to an interface, not an implementaion". The interface mentioned here is not a specific programming language. The interface in, it is language-independent and refers to a list of functions provided by the developer to the user. It is very important to understand this. Interfaces are implemented by the keyword interface in the Java language. Java does not support multiple inheritance of classes, but supports multiple inheritance of interfaces. Java developers are very familiar with interfaces. Python does not need Java design at all, but You can learn from the advantages of the interface.

**Let's first use an example to understand what problem the interface solves. **

For example, you are implementing a picture upload function, and currently use Qiniu Cloud for storage. Your class may look like this.

classQnyImageStore(object):

 def getToken():
  pass

 def upload_qny(self,image):print("Qny upload.")
  # do something

 def download_qny(self,image):print("Qny download.")
  # do something

In actual development, there are many lines of code and more than three functions. It is called from hundreds to thousands of places, scattered in hundreds of files. After a period of time, the company built its own private cloud, and requested that Qiniu Cloud can no longer be used. It must be changed to its own Cloud Storage, so you have to rewrite a class:

classOwnImageStore(object):

 def upload_own(self,image):print("Qny upload.")
  # do something

 def download_own(self,image):print("Qny download.")
  # do something

Then you replace all the places you use Qiniu, you also need to replace the name of the function, and finally you have to test multiple times, where you haven't considered any part of your life, and you run an error. It was finally changed. Suddenly one day, the demand changed again. Because my cloud service often had problems, I had to switch to Alibaba Cloud. After the painful toss of the last time, when I saw that this time I was going to change, I vomited blood directly.

In fact, the problem is that the code you write is not general enough and the naming is not abstract enough. If the function naming of your class uses upload and download, the amount of code you modify may be reduced to half, just replace the class name. In fact, we can use interfaces to reduce the amount of code changes: through the separation of interfaces and implementations, encapsulate unstable implementations and expose stable interfaces. When the upstream and downstream systems use the functions developed by us, they only need to use the function list declared in the interface, so that when the implementation changes, the code of the upstream system basically does not need to be changed, so as to reduce coupling and improve scalability . The following provides an interface-based code implementation method on this issue.

Define an interface

from abc import ABCMeta, abstractmethod

classImageStore(metaclass = ABCMeta):

 @ abstractmethod
 def upload(self,image): 
  pass
  # raise NotImplementedError

 @ abstractmethod
 def download(self,image): 
  pass
  # raise NotImplementedError

After the interface is defined, any class that inherits the interface must rewrite the upload and download methods to use it correctly, otherwise an exception will be thrown. Here we don’t need to throw an exception in the interface. The standard library abc is already We have done these tasks.

Define class, inherit interface

The purpose is actually to enforce constraints, that is to say, upload and download methods must be implemented and checked at compile time to ensure the robustness of the program.

classOwnImageStore2(ImageStore):

 def upload(self,image):print("Own upload.")
  # do something

 def download(self,image):print("Own download.")
  # do something

classQnyImageStore2(ImageStore):

 def getToken():
  pass

 def upload(self,image):print("Qny upload.")

 def download(self,image):print("Qny download.")
  # do something

Next, we define an interface that can automatically select the method of calling the corresponding object according to the type.

classUsedStore(object):

 def __init__(self, store):if not isinstance(store, ImageStore): raise Exception('Bad interface')
  self._store = store

 def upload(self):
  self._store.upload('image')

 def download(self):
  self._store.download('image')

Finally, we can specify in the configuration file which specific interface we are using:

# In other files, it should be called like this
img =QnyImageStore2()
# img =OwnImageStore2()Put these in the configuration file, you only need to update the configuration file to replace
store =UsedStore(img)
store.upload()
store.download()

In this way, to add new image storage later, we only need to add the corresponding class, inherit the interface, and modify the configuration file to reduce a lot of code modification work.

Introduction to Python abstract base classes (PEP3119)

The python standard library abc, the full name is Abstract Base Classes, which provides the following functions:

Fundamental:

In the field of object-oriented programming, design patterns that interact with objects can be divided into two basic categories, namely "call" and "check".

Calling refers to interacting with the object by calling the method of the object. Usually, this is combined with polymorphism, so calling a given method may run different code depending on the type of object.

Inspection refers to the ability of external code (outside the method of an object) to inspect the type or attributes of the object and determine how to deal with the object based on this information.

Both usage modes serve the same general purpose, that is, they can support the processing of diverse and possibly novel objects in a unified manner, but at the same time allow for customized processing decisions for each different type of object.

In the classic OOP theory, call is the preferred design pattern, and inspection is discouraged because inspection is considered a product of an earlier style of procedural programming. However, in reality, this view is too dogmatic and rigid, leading to a certain design rigidity, which is very different from the dynamic nature of languages such as Python.

In particular, it is often necessary to handle objects in a way that the creator of the object class cannot predict. Built into every object method that meets every possible user need of that object is not always the best solution. Moreover, there are many powerful scheduling philosophies that contrast sharply with classical OOP behavior requirements that are strictly encapsulated in objects, such as rules or pattern matching-driven logic

On the other hand, one of the criticisms of inspection by classic OOP theorists is the lack of formalism and the special nature of the inspected content. In languages such as Python, almost any aspect of an object can be reflected and directly accessed through external code. There are many different ways to test whether an object conforms to a specific protocol. For example, if you ask "Is this object a variable sequence container?", you can look for the base class of "list", or you can look for a method named ", getitem". But please note that although these tests may seem obvious, they are not correct because one will produce false negatives and the other will produce false positives.

The generally agreed remedy is to standardize the tests and group them into formal forms. It is easiest to do this through inheritance mechanisms or some other way, by associating a set of standard testable properties with each class. Each test comes with a set of promises: it contains promises about the general behavior of the class, as well as promises about other available class methods.

PEP proposes a special strategy for organizing these tests, called Abstract Base Class (ABC). ABC is just a Python class added to the inheritance tree of an object to send certain functions of the object to an external inspector. Use isinstance() to complete the test, and the presence of a specific ABC means that the test has passed.

In addition, ABC defines the minimum set of methods for establishing this type of characteristic behavior. The code that distinguishes objects based on their ABC type can be trusted that these methods will always exist. Each of these methods is accompanied by a generalized abstract semantic definition described in the ABC document. The semantic definitions of these standards are not mandatory, but they are strongly recommended.

Like everything else in Python, these promises are of the nature of a gentleman agreement. In this case, this means that although the language does implement some of the promises made in ABC, the implementer of the concrete class must ensure that there is Keep the next.

After reading the above description, you can simply understand that ABC is a base class. Inheriting it, you can write an interface similar to java. The methods in the interface will always exist, and you can use it with confidence and no need to probe.

PEP3119 also gave sample codes for you to understand:

from abc import ABCMeta, abstractmethod

classA(metaclass=ABCMeta):
 @ abstractmethod
 def foo(self): pass

A()  # raises TypeError

classB(A):
 pass

B()  # raises TypeError

classC(A):
 def foo(self):print(42)C()  # works

I don’t want to talk about it. I hope you can use ABC correctly. At the same time, I strongly recommend that you learn Python. Just look at the official Python documentation and the PEP proposal. Here is the most authoritative explanation.

In addition, the setting mode is also a very important programming technique and way of programming. It is a basic skill. If the basic skill is not enough, you don't know how to appreciate and taste if you put a fighter in front of you.

Once you have mastered the design pattern and look at other people’s code, you will have a golden eye, which is a fighter jet and which is a tractor. It is also very helpful for your own learning and improvement. The code you write will also be more maintainable and readable. Scalability, flexibility.

If you are interested in design patterns, then join and study with me. The classmates who bought design patterns from the picture below, add my friend (somenzz), cash back 12 yuan, and take you to join the big group to exchange Python technology, Don't learn alone, have no friends, and be ignorant.

The beauty of design patterns-Wang Zheng

Recommended Posts

How to program based on interfaces in Python
How to write a confession program in python
How to save the python program
How to omit parentheses in Python
How to install Python 3.8 on CentOS 8
How to install Python 3.8 on Ubuntu 18.04
How to write classes in python
How to filter numbers in python
How to read Excel in Python
How to install Python on CentOS 8
How to view errors in python
How to write return in python
How to understand variables in Python
How to clear variables in python
How to use SQLite in Python
How to use and and or in Python
How to delete cache files in python
How to represent null values in python
How to save text files in python
How to write win programs in python
How to run id function in python
How to install third-party modules in Python
How to custom catch errors in python
How to write try statement in python
How to define private attributes in Python
R&D: How To Install Python 3 on CentOS 7
How to add custom modules in Python
How to understand global variables in Python
How to view installed modules in python
How to install Python2 on Ubuntu20.04 ubuntu/focal64
How to debug python program using repr
How to open python in different systems
How to sort a dictionary in python
How to add background music in python
How to represent relative path in python
How to upgrade all Python libraries on Ubuntu 18.04
How to use the round function in python
How to use the zip function in Python
How to install python in ubuntu server environment
How to simulate gravity in a Python game
How to use the format function in python
How to play happily with Python3 on Ubuntu
How to use code running assistant in python
How to set code auto prompt in python
[Practice] How to install python3.6 on Ubuntu system
Teach you how to write games in python
How to delete files and directories in python
How to install the downloaded module in python
How to perform continuous multiplication calculation in python
How to install Hadoop in standalone mode on Ubuntu 18.04
How to configure a fixed IP based on Ubuntu 18.04
How to understand the introduction of packages in Python
How to understand a list of numbers in python
Example of how to automatically download pictures in python
How to save IE as an attachment in python
How to create a Python virtual environment in Ubuntu 14.04
How to set a fixed IP based on Ubuntu 16.04
How to comment python code
How to learn python quickly
How to uninstall python plugin
How to understand python objects