First, a four-person group is provided.Decorator ModeDefinition:DynamicToObjectAdd someAdditional responsibilities.
Let's talk about the advantages of this mode: authentication, permission check, logging, checking parameters, locking, and so on. These functions are irrelevant to the system business, but are required by the system, to be more clear, it is Aspect-oriented programming (AOP).AOPIrrelevant to the businessCodeIt is very clean to cut out from the system,Decorator ModeThis article focuses onDecorator ModeInPythonSo I will not describe too muchDecorator ModeFor more information about this model, see the four-person group's classic design model.
InPythonMediumDecorator ModeYou can followProgramming LanguageFor exampleC ++, JavaButPythonIn the ApplicationDecorationThe conceptual capabilities are far more than that,PythonIt provides a syntax and a programming feature to enhance this feature.PythonThe provided syntax is the modifier syntax.(Decorator), As follows:
@ Aoo
DefFoo ():Pass
DefAoo (FN ):
ReturnFN
I will not explain too much about the decorator syntax here, because the decorator syntax is based on another programming feature that I will introduce. After I have introduced another programming feature, I believe that you will have a deeper understanding of the decoration device syntax.
A very important programming feature "closure"(Closure)Grand debutJavaThe list of feature candidates for the next version)
InPython,PHP,Perl,Ruby,JavascriptAnd other dynamic languages have implemented the closure feature,Why is this feature so important? Let's take a look at some of its popular definitions:
Objects in the OO programming paradigm are "data objects that integrate functions", so closures are "function objects that integrate data"
To sum up, we can use a very good statement: objects are data with behaviors, while closures are data-related behaviors.
On the leftFoo1It is just a common embedded function, andBooIs a closure,
def Foo (x ): Y = x def foo1 (): A = 1 return a return foo1 |
DefAoo (A, B ): C = DefBoo(X ): X = B + 1 Return x Return boo |
|
BooThe special feature is that external variables are referenced.B, WhenAooAfter the return value is (Boo) Always exist, thenBWill always exist.
The above knowledge may take some time to digest. If you think you have mastered this knowledge, let's go back to the question and see how these language features are implemented.PythonMediumDecoration.
Let's take a look at a simple example and then go deeper. This example shows how to implement the lock function?
The specific requirement is as follows: I have an object that implements some functions and provides some interfaces for other modules to call. This object runs in a concurrent environment, therefore, I need to synchronize interface calls. The first version of the Code is as follows:
ClassFoo (object ):
Def _ Init __(Self ,...) :
Self. Lock = threading. Lock ()
DefInterface1 (self ,...) :
Self. Lock. Acquire ()
Try:
Do something
Finally:
Self. Lock. Release ()
DefInterface2 (self ,...) :
Same as interface1 ()
This version of code has obvious problems, that is, each interface function has the same lock./Unlocking code, repeated code brings about more types, more reading, more maintenance, and more modifications. Most importantly,ProgramThe staff's focus on the business has been dispersed.And pay attention to the fact that the real business code is defined in the distance function2Even if your monitor is a wide screen, this may cause some reading difficulties.
You intuitively think that the code can be incorporated into a function for reuse, but note that the code is not a complete code block, but in the middleEmbedded Business Code.
Now we use the decorator syntax to improve this part of code.2Version code:
DefSync (func ):
DefWrapper (* ARGs, ** kV ):
Self = ARGs [0]
Self. Lock. Acquire ()
Try:
ReturnFunc (* ARGs, ** kV)
Finally:
Self. Lock. Release ()
ReturnWrapper
ClassFoo (object ):
Def _ Init __(Self ,...) :
Self. Lock = threading. Lock ()
@ Sync
DefInterface1 (self ,...) :
Do something
@ Sync
DefInterface2 (self ,...) :
Do something
The first parameter of a decorator function is the function object to be decorated, and the decorator function must return a function object. For example Sync Function, when it is decorated Interface1 Parameter Func The value is Interface1 , The return value is Wrapper , But the class Foo Instance Interface1 When called, what is actually called is Wrapper Function, in Wrapper The function body indirectly calls the actual Interface1 ; When Interface2 When called, it is also called Wrapper Function, but because Func Already changed Interface2 , So it will be indirectly called to use the actual Interface2 Function.
Benefits of using the decorator Syntax:
- The amount of code is greatly reduced. Less code means less maintenance, less reading, and less typing, which is advantageous (reusable and maintainable)
- Most of the user's focus is on the Business Code, and the code of addition and subtraction locks is missing, which improves readability.
Disadvantages:
- Business ObjectFooThere is a non-business data memberLock, Very eye-catching;
- A considerable degree of coupling,WrapperThe first parameter of must be the object itself, and there must beLockThe object exists, which adds restrictions to the customer object and is not very comfortable to use.
Let's think about it further:
- LockThe object must be placed inFoo?
- Enter@ SyncStill annoying and repetitiveManualWork. If one is missing, it will still cause inexplicable runtime errors. Why not concentrate on it?
To solve the preceding disadvantages3The version code is as follows:
Class Decorateclass (object ):
Def Decorate (Self ):
For Name, FN In Self. ITER ():
If Not Self. Filter (name, FN ):
Continue
Self. Operate (name, FN)
Class Lockerdecorator (decorateclass ):
Def _ Init __ (Self, OBJ, lock = threading. rlock ()):
Self. OBJ = OBJ
Self. Lock = Lock
Def ITER (Self ):
Return [(Name, getattr (self. OBJ, name )) For Name In Dir (self. OBJ)]
Def Filter (self, name, FN ):
If Not Name. startswith ( ' _ ' ) And Callable (FN ):
Return True
Else :
Return False
Def Operate (self, name, FN ):
Def Locker (* ARGs, ** kV ):
Self. Lock. Acquire ()
Try :
Return FN (* ARGs, ** kV)
Finally :
Self. Lock. Release ()
Setattr (self. OBJ, name, locker)
Class Foo (object ):
Def _ Init __ (Self ,...) :
...
Lockerdecorator (Self). Decorate ()
Def Interface1 (self ,...) :
Do something
Def Interface2 (self ,...) :
Do something
decoration of object functions is a more general function, not limited to interface locking, I used 2 classes to complete this function, decorateclass is a base class, only the algorithm Code (Template Method) , lockerdecorat or Implemented the lock function for objects , ITER is an iterator, defines how to traverse members in an object (including data members and member functions ), filter is a filter, A member who defines the rule can become an interface, operate is an execution function, the object interface lock function is specifically implemented.
In businessFooOf_ Init __In the function, you only need to add a line of code at the end:LockerdecoratOr(Self). Decorate ()To lock the object.
If the interfaces provided by your object are special, you can simply rewrite them.FilterOr inheritLockerdecoratOrAnd OverwriteFilterIn addition, if you want to use other decorative functions, you can writeDecorateclassAnd implementITER,FilterAndOperateThree functions.
Reprinted from: Python and decorator modes