I understand how to write a decorator.
A decorator, as the name implies, decorates. What you decorate is already a function, a function. Another method.
I understand. It's hard. I understand the decorator.
Takeshi muttered and started running as if he had been flipped. But the signal started blinking and stopped. Yes, he follows the traffic rules.
And think about leaving time.
Humanity is what I want to use when I can write. However, when I actually want to use it, I don't know where to use it. I can't think of an effective use.
Such a person.
Yes! I don't even know!
No, but maybe I've come to understand a little.
Why use a decorator?
-Use decorators for unwanted redundancy elimination and DRY
--Use decorators to improve readability
I can think of something like this. This is often mentioned as an advantage of using it.
This is nothing wrong! Overwhelmingly correct! Oh, I'm sure it's correct!
But it's just that I don't know where to use it.
Because, for the reasons mentioned above, there are many other ways to do it, right? For example, is there inheritance? Isn't it okay to just use it as a function? You're used to it, right? I don't want to bother to write something like a decorator. I think so, but are you complaining?
Do you think? Don't you think I think.
So why dare to use a decorator?
To think about it, we need to pay attention to the ** meaning ** of the processing of the code. The bottom line here is that we use decorators for ** separation of business logic **.
You've probably seen an example like this as the first step in decorating.
from functools import wraps
def trace_func_call(func):
@wraps(func)
def wrapper(*arg):
print(func.__name__ + ' is called.')
return func(*arg)
return wrapper
@trace_func_call
def spam(s):
print((s + '!') * 5)
@trace_func_call
def ham(s):
print((s + '?') * 5)
spam('egg')
ham('sausage')
Execution result
spam is called.
egg!egg!egg!egg!egg!
ham is called.
sausage?sausage?sausage?sausage?sausage?
A decorator that displays it each time a function is called.
At this time, the role that the decorator plays is not business logic, isn't it?
The example is super-appropriate, but the processing you want to do as business logic is the processing of the spam
and ham
functions, isn't it?
It's a crappy guy who repeats 5 times with !
Or ?
As an argument.
At that time, displaying the function call is not the business logic, but the logic to implement it because it is necessary for management. Their logic is semantically different.
You can use decorators to separate management logic from business logic. In other words, based on what you want to do, decorators are the ones that realize the intention of separating the business logic, which is the main purpose of the code, from the management logic in a neat way. Of course, I don't mean to say that this is the only role of the decorator, but it gives us great suggestions on how to use the decorator.
Next is a little more practical. This is a sample decorator from Raymond Hettinger's talk ** "Transforming Code into Beautiful, Idiomatic Python" ** at PyCon US 2013.
Let's start with the original "less desirable" code.
def web_lookup(url, saved={}):
if url in saved:
return saved[url]
page = urllib.urlopen(url).read()
saved[url] = page
return page
Click here for a better version of the above code using a decorator.
def cache(func):
saved = {}
@wraps(func)
def newfunc(*args):
if args in saved:
return saved[args]
result = func(*args)
saved[args] = result
return result
return newfunc
@cache
def web_lookup(url):
return urllib.urlopen(url).read()
The web_lookup
function is a function that gets the web page of the specified URL.
At that time, it has a function to cache the acquired pages.
It's a very short code, but you can see that the functionality of this code is semantically divided as follows:
--Business logic -> Get the web page of the specified URL --Administrative logic -> Get the web page of the specified URL
In the original code, the caching functionality is provided by a dictionary of arguments passed to the web_lookup
function.
In other words, the function itself is an implementation that incorporates the functionality of business logic and administrative logic.
On the other hand, in better code, the function implements only the business logic, and the administrative logic is implemented by the closed decorator. You'll find that doing this clearly separates the business logic and improves the readability and maintainability of the code.
The amount of code has increased with the implementation of decorators, but I feel that calling it "beautiful code" is a very pythonic feeling.
By the way, these cache decorator patterns are standard patterns, so it's not difficult and you should definitely try it.
By the way, I think the code of the quoted lecture slides is wrong ... So I am modifying the code I wrote above. This is the decorator. You're wrong, right? https://speakerdeck.com/pyconslides/transforming-code-into-beautiful-idiomatic-python-by-raymond-hettinger-1
Then another one.
Especially when using 2.x and the character code of the input is unknown, I'm really tired of decoding somehow by handling the character string, somehow unicode, etc., so in the internal processing I use chardet with a decorator Let's make everything unicode and process it.
It may be useful when writing a little tool.
import chardet
def unicode_conv(func):
def wrapper(*args):
f = lambda x: x.decode(chardet.detect(x)['encoding'])
args = [f(arg) if type(arg) != unicode else arg for arg in args]
return func(*args)
return wrapper
def funcA(*args):
for arg in args:
print(repr(arg))
@unicode_conv
def funcB(*args):
for arg in args:
print(repr(arg))
funcA('shrubbery')
funcB('shrubbery')
funcB(u'shrubbery')
Execution result
'shrubbery'
u'shrubbery'
u'shrubbery'
Recommended Posts