current position:Home>How to program based on interfaces using Python

How to program based on interfaces using Python

2022-01-31 14:01:44 somenzz

Software industry , The only constant is change . The product manager will change , Product demand will change , The code should also change .

Different code designs , The workload caused by change is even different , Some need to change every time , Almost a refactoring , Some only need to modify one configuration file , Or add a line of code to the class . Of course, better code design , Due to its good scalability , High cohesion , Low coupling , Therefore, it is easy to maintain , Respond to changes with less changes . If you can have good code design , We need to learn design patterns . What I share with you today is in Python in , How to program based on interface .

1994 year GoF Of 《 Design patterns 》 An important principle in a book is : Programming based on interfaces rather than implementation , The English source is 「Program to an interface,not an implementaion」, What is said here interface, It's not an interface in a specific programming language , It has nothing to do with language , It refers to a list of functions provided by developers to users , It is very important to understand this . Interface in java There are keywords in the language interface To achieve ,java Multiple inheritance of classes is not supported , But it supports multiple inheritance of interfaces , Where java Developers are very familiar with the interface ,Python In fact, there is no need to Java That kind of design , But we can learn from the advantages of the interface .

Let's take an example to find out what problem the interface solves .

For example, you are implementing a picture upload function , At present, seven cattle cloud is used to store , Your class may be like this .

class QnyImageStore(object):

    def getToken():
        pass

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

 Copy code 

In actual development , There will be many lines of code , There are more than three functions , It's called from hundreds of places , Scattered in hundreds of files . After a while , The company built its own private cloud , It is required that qiniu cloud can no longer be used , Change to your own cloud storage , So you have to rewrite a class :

class OwnImageStore(object):

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

Then you go where you use seven cows , Replace all , Also replace the name of the function , Finally, we have to test many times , Where in life does not take into account , Operation error reporting . It's not easy to change , And then one day , Demand has changed again , Because their cloud services often have problems , So I want to change Alibaba cloud . After the last toss and turn , See this change again , Direct hematemesis .

In fact, the problem is that the code you write is not general enough , Naming is not abstract enough . If the function name of your class uses upload,download such , Then the amount of code you modify may be reduced to half , Just replace the class name . actually , We can use interfaces to reduce the amount of code changes : Through the interface and realize the mode of phase separation , Encapsulation of unstable implementations , Exposed stable interface . When the upstream and downstream systems use the functions we developed , Just use the list of functions declared in the interface , So when the implementation changes , The upstream system code basically doesn't need to be changed , To reduce coupling , Improve scalability . Here's the question , Provide an interface based code implementation .

Define an interface

from abc import ABCMeta, abstractmethod

class ImageStore(metaclass = ABCMeta):
    
 @abstractmethod
    def upload(self,image): 
        pass
        #raise NotImplementedError

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

After defining the interface , Any class that inherits this interface should use it correctly , Must be rewritten upload and download Method , Otherwise, exceptions will be thrown , Here we don't need to throw exceptions in the interface by ourselves , Standard library abc We have done these jobs for us .

#### Defining classes , Inherited interface

The purpose is actually to impose constraints , That is to say, it must be realized upload and download Method , Check at compile time , Ensure the robustness of the program .

class OwnImageStore2(ImageStore):

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

 

class QnyImageStore2(ImageStore):

    def getToken():
        pass

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

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

 Copy code 

Next , We define an interface , You can automatically select the method to call the corresponding object according to the type .

class UsedStore(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')
 Copy code 

Last , We can specify which specific interface we use in the configuration file :


# In other files , It should be called like this 
img = QnyImageStore2()
# img = OwnImageStore2()  Put these in the configuration file , Just update the configuration file to replace  
store = UsedStore(img)
store.upload()
store.download()
 Copy code 

such , Add new picture storage later , We just need to add the corresponding class , Inherited interface , And modify the configuration file , Reduce a lot of code modification work .

Python Introduction to abstract base classes (PEP3119)

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

  • An overload isinstance() and issubclass() Methods
  • A new module abc As “Abstract Base Classes Support framework ”. It defines a for abc And a decorator that can be used to define abstract methods
  • Specific abstract base classes for containers and iterators , Will be added to collections modular

The basic principle

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 an object by calling its methods . Usually , This will be used in conjunction with polymorphism , Therefore, calling a given method may run different code according to the type of object .

Checking refers to external code ( Outside the method of the object ) Check the type or property of the object , And the ability to decide how to deal with the object based on this information .

Both usage patterns serve the same general purpose , That is, it can support the processing of various and possibly novel objects in a unified way , But it also allows you to customize processing decisions for each different type of object .

In the classical OOP In theory , Call is the preferred design pattern , And inspection is not encouraged , Because inspection is considered to be the product of an earlier process programming style . however , actually , This view is too dogmatic and rigid , It leads to some kind of design rigidity , And Python The dynamic characteristics of languages like are very different .

especially , You usually need to handle objects in a way that the creator of the object class cannot expect . Built into every object method that meets every possible user need of the object , Not always the best solution . and , There are many powerful scheduling philosophies and classics strictly encapsulated in objects OOP In stark contrast to behavioral requirements , For example, rules or pattern matching driven logic

On the other hand , classical OOP One of the criticisms of theorists on inspection is the lack of formalism and the special nature of the inspected content . In such as Python In such a language , 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 “ Whether this object is a variable sequence container ?”, You can find “ list ” Base class of , Or you can look for something called “ getitem” Methods . But notice , Although these tests seem obvious , But none of them is correct , Because one of them will produce a false negative , And the other will produce a false positive .

The generally agreed remedy is to standardize testing , And group them into formal forms . Through inheritance mechanism or some other way , By associating a standard set of testable properties with each class , It's easiest to do this . Each test comes with a set of commitments : It contains commitments about the general behavior of classes , And commitments about other available class methods .

PEP A special strategy is proposed for organizing these tests , It's called an abstract base class (ABC). ABC Just add to the inheritance tree of the object Python class , To send some functions of the object to the external inspector . Use isinstance() To complete the test , And specific ABC The existence of means that the test has passed .

Besides ,ABC The minimum method set for establishing the characteristic behavior of this type is defined . Based on the ABC Code that distinguishes objects by type can be trusted , These methods will always exist . Each of these methods comes with ABC The generalized abstract semantic definition described in the document . The semantic definitions of these standards are not mandatory , But it is strongly recommended to use .

image Python Like everything else in , These commitments are in the nature of gentleman's agreement , under these circumstances , This means that although the language does execute ABC Some commitments made in , But the implementer of a concrete class must ensure that Keep the rest .

After reading the above description , You can simply understand it as ,ABC Is a base class , Inherit it , You can write one similar to java The interface of , The methods in the interface will always exist , Safe to use , No more detection is needed .

PEP3119 Sample code is also provided for you to understand :

from abc import ABCMeta, abstractmethod

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

A()  # raises TypeError

class B(A):
    pass

B()  # raises TypeError

class C(A):
    def foo(self): print(42)

C()  # works
 Copy code 

Don't say more , I hope you can use it correctly ABC, At the same time, we strongly recommend , Study Python, Just look Python Official documents and PEP The proposal , Here is the most authoritative explanation .

Besides , Setting mode is also a very important programming skill and programming way , It's basic skill , If basic skills are not enough , Put a fighter in front of you , You don't know how to appreciate and taste .

Master the design pattern , Look at other people's code , You will have golden eyes , Which are fighters , Which are tractors , It's also very helpful for me and my study , The code written will also be more maintainable , Readability , Extensibility , flexibility .

copyright notice
author[somenzz],Please bring the original link to reprint, thank you.
https://en.pythonmana.com/2022/01/202201311401369516.html

Random recommended