Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikibooksThe Free Textbook Project
Search

Python Programming/Decorators

From Wikibooks, open books for an open world
<Python Programming
Previous: IdiomsIndexNext: Context Managers


Duplicated code is recognized as bad practice in software for lots of reasons, not least of which is that it requires more work to maintain. If you have the same algorithm operating twice on different pieces of data you can put the algorithm in a function and pass in the data to avoid having to duplicate the code. However, sometimes you find cases where the code itself changes, but two or more places still have significant chunks of duplicated boilerplate code. A typical example might be logging:

defmultiply(a,b):result=a*blog("multiply has been called")returnresultdefadd(a,b):result=a+blog("add has been called")returnresult

In a case like this, it's not obvious how to factor out the duplication. We can follow our earlier pattern of moving the common code to a function, but calling the function with different data is not enough to produce the different behavior we want (add or multiply). Instead, we have to pass afunction to the common function. This involves a function that operates on a function, known as ahigher-order function.

Decorator in Python is a syntax sugar for high-level function.

Minimal example of property decorator:

>>>classFoo(object):...@property...defbar(self):...return'baz'...>>>F=Foo()>>>print(F.bar)baz

The above example is really just a syntax sugar for codes like this:

>>>classFoo(object):...defbar(self):...return'baz'...bar=property(bar)...>>>F=Foo()>>>print(F.bar)baz

Minimal Example of generic decorator:

>>>defdecorator(f):...defcalled(*args,**kargs):...print('A function is called somewhere')...returnf(*args,**kargs)...returncalled...>>>classFoo(object):...@decorator...defbar(self):...return'baz'...>>>F=Foo()>>>print(F.bar())Afunctioniscalledsomewherebaz

A good use for the decorators is to allow you to refactor your code so that common features can be moved into decorators. Consider for example, that you would like to trace all calls to some functions and print out the values of all the parameters of the functions for each invocation. Now you can implement this in a decorator as follows:

#define the Trace class that will be#invoked using decoratorsclassTrace(object):def__init__(self,f):self.f=fdef__call__(self,*args,**kwargs):print("entering function "+self.f.__name__)i=0forarginargs:print("arg{0}:{1}".format(i,arg))i=i+1returnself.f(*args,**kwargs)

Then you can use the decorator on any function that you defined by:

@Tracedefsum(a,b):print"inside sum"returna+b

On running this code you would see output like

>>>sum(3,2)enteringfunctionsumarg0:3arg1:2insidesum

Alternately, instead of creating the decorator as a class, you could have used a function as well.

defTrace(f):defmy_f(*args,**kwargs):print("entering "+f.__name__)result=f(*args,**kwargs)print("exiting "+f.__name__)returnresultmy_f.__name=f.__name__my_f.__doc__=f.__doc__returnmy_f#An example of the trace decorator@Tracedefsum(a,b):print("inside sum")returna+b#if you run this you should see>>>sum(3,2)enteringsuminsidesumexitingsum5

Remember it is good practice to return the function or a sensible decorated replacement for the function so that decorators can be chained.

Previous: IdiomsIndexNext: Context Managers
Retrieved from "https://en.wikibooks.org/w/index.php?title=Python_Programming/Decorators&oldid=4070804"
Category:

[8]ページ先頭

©2009-2025 Movatter.jp