Skip to content

Commit 4631851

Browse files
committed
add raw resource of python weekly #243
1 parent 806c640 commit 4631851

8 files changed

Lines changed: 1507 additions & 0 deletions
Lines changed: 389 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,389 @@
1+
原文:[5 reasons you need to learn to write Python decorators](https://www.oreilly.com/ideas/5-reasons-you-need-to-learn-to-write-python-decorators)
2+
3+
---
4+
5+
Decorators can massively magnify the positive impact of the code you write.
6+
7+
By [Aaron
8+
Maxwell](https://www.oreilly.com/people/27097813-9a87-49f9-9fe3-84144509ace3)
9+
10+
May 5, 2016
11+
12+
![Dragons](https://d3tdunqjn7n0wj.cloudfront.net/360x240/dragons-
13+
1124668_1400-d7649773673ddae0700617e719275b81.jpg) Dragons (source:
14+
[Pixabay](https://pixabay.com/en/dragons-china-thailand-ornament-1124668/)).
15+
16+
If you're interested in learning how to use Python decorators and want to
17+
write more robust, reliable, and maintainable Python code, you'll want to
18+
check out Aaron Maxwell's online course, [Python–Beyond the
19+
Basics](https://www.oreilly.com/online-courses/python-beyond-
20+
basics.html?intcmp=il-prog-olreg-article-
21+
oltrain_5_reasons_you_need_to_learn_to_write_python_decorators_inline).
22+
23+
Python decorators are so easy to use. Anyone who knows how to write a Python
24+
function can learn to use a decorator:
25+
26+
[code]
27+
28+
@somedecorator
29+
def some_function():
30+
print("Check it out, I'm using decorators!")
31+
32+
[/code]
33+
34+
But _writing_ decorators is a whole different skill set. And it’s not trivial;
35+
you have to understand:
36+
37+
* closures
38+
* how to work with functions as first-class arguments
39+
* variable arguments
40+
* argument unpacking, even
41+
* some details of how Python loads its source code.
42+
43+
This all takes significant time to understand and master. And you already have
44+
a backlog of things to learn. Is this worth your time?
45+
46+
For me, the answer has been "a thousand times, YES!" And odds are it will be
47+
for you, too. What are the key benefits of writing decorators...what they let
48+
you do easily and powerfully, in your day-to-day development?
49+
50+
## Analytics, logging, and instrumentation
51+
52+
Especially with large applications, we often need to specifically measure
53+
what’s going on, and record metrics that quantify different activities. By
54+
encapsulating such noteworthy events in their own function or method, a
55+
decorator can handle this requirement very readably and easily.
56+
57+
[code]
58+
59+
from myapp.log import logger
60+
61+
def log_order_event(func):
62+
def wrapper(*args, **kwargs):
63+
logger.info("Ordering: %s", func.__name__)
64+
order = func(*args, **kwargs)
65+
logger.debug("Order result: %s", order.result)
66+
return order
67+
return wrapper
68+
69+
@log_order_event
70+
def order_pizza(*toppings):
71+
# let's get some pizza!
72+
73+
[/code]
74+
75+
The same approach can be used to record counts or other metrics.
76+
77+
## Validation and runtime checks
78+
79+
Python’s type system is strongly typed, but very dynamic. For all its
80+
benefits, this means some bugs can try to creep in, which more statically
81+
typed languages (like Java) would catch at compile time. Looking beyond even
82+
that, you may want to enforce more sophisticated, custom checks on data going
83+
in or out. Decorators can let you easily handle all of this, and apply it to
84+
many functions at once.
85+
86+
Imagine this: you have a set of functions, each returning a dictionary, which
87+
(among other fields) includes a field called "**summary**." The value of this
88+
summary must not be more than 80 characters long; if violated, that’s an
89+
error. Here is a decorator that raises a **ValueError** if that happens:
90+
91+
[code]
92+
93+
def validate_summary(func):
94+
def wrapper(*args, **kwargs):
95+
data = func(*args, **kwargs)
96+
if len(data["summary"]) > 80:
97+
raise ValueError("Summary too long")
98+
return data
99+
return wrapper
100+
101+
@validate_summary
102+
def fetch_customer_data():
103+
# ...
104+
105+
@validate_summary
106+
def query_orders(criteria):
107+
# ...
108+
109+
@validate_summary
110+
def create_invoice(params):
111+
# ...
112+
113+
[/code]
114+
115+
## Creating frameworks
116+
117+
Once you master writing decorators, you'll be able to benefit from the simple
118+
syntax of using them, which lets you add semantics to the language that are
119+
easy to use. It's the next best thing to being able to extend the syntax of
120+
Python itself.
121+
122+
In fact, many popular open source frameworks use this. The webapp framework
123+
Flask uses it to route URLs to functions that handle the HTTP request:
124+
125+
[code]
126+
127+
# For a RESTful todo-list API.
128+
@app.route("/tasks/", methods=["GET"])
129+
def get_all_tasks():
130+
tasks = app.store.get_all_tasks()
131+
return make_response(json.dumps(tasks), 200)
132+
133+
@app.route("/tasks/", methods=["POST"])
134+
def create_task():
135+
payload = request.get_json(force=True)
136+
task_id = app.store.create_task(
137+
summary = payload["summary"],
138+
description = payload["description"],
139+
)
140+
task_info = {"id": task_id}
141+
return make_response(json.dumps(task_info), 201)
142+
143+
@app.route("/tasks/<int:task_id>/")
144+
def task_details(task_id):
145+
task_info = app.store.task_details(task_id)
146+
if task_info is None:
147+
return make_response("", 404)
148+
return json.dumps(task_info)
149+
150+
[/code]
151+
152+
Here you have a global object called **app**, with a method called **route**,
153+
taking certain arguments. That **route** method returns a decorator that is
154+
applied to the handler function. What’s going on beneath the hood is pretty
155+
intricate and complicated, but from the perspective of the person using Flask,
156+
all that complexity is completely hidden.
157+
158+
Using decorators in this way also shows up in stock Python. For example, fully
159+
using the object system relies on the **classmethod** and **property**
160+
decorators:
161+
162+
[code]
163+
164+
class WeatherSimulation:
165+
def __init__(self, **params):
166+
self.params = params
167+
168+
@classmethod
169+
def for_winter(cls, **other_params):
170+
params = {'month': 'Jan', 'temp': '0'}
171+
params.update(other_params)
172+
return cls(**params)
173+
174+
@property
175+
def progress(self):
176+
return self.completed_iterations() / self.total_iterations()
177+
178+
[/code]
179+
180+
This class has three different def statements. But their semantics are all
181+
different:
182+
183+
* the constructor is a normal method
184+
* for_winter is a classmethod providing a kind of factory, and
185+
* progress is read-only, dynamic attribute
186+
187+
The simplicity of the **@classmethod** and **@property** decorators makes it
188+
easy to extend Python’s object semantics in everyday use.
189+
190+
## Reusing impossible-to-reuse code
191+
192+
Python gives you some very powerful tools for encapsulating code into an
193+
easily reusable form, with an expressive function syntax, functional
194+
programming support, and a full-featured object system. However, there are
195+
some patterns of code reuse which can’t be captured by these alone.
196+
197+
Consider working with a flakey API. You make requests to something that speaks
198+
JSON over HTTP, and it works correctly 99.9% of the time. But… a small
199+
fraction of all requests will cause the server to return an internal error,
200+
and you need to retry the request. In that case, you’d implement some retry
201+
logic, like so:
202+
203+
[code]
204+
205+
resp = None
206+
while True:
207+
resp = make_api_call()
208+
if resp.status_code == 500 and tries < MAX_TRIES:
209+
tries += 1
210+
continue
211+
break
212+
process_response(resp)
213+
214+
[/code]
215+
216+
Now imagine you have dozens of functions like **make_api_call()**, and they
217+
are called all over the codebase. Are you going to implement that while loop
218+
everywhere? Are you going to do it again every time you add a new API-calling
219+
function? This kind of pattern makes it hard to not have boilerplate code.
220+
Unless you use decorators. Then it’s quite simple:
221+
222+
[code]
223+
224+
# The decorated function returns a Response object,
225+
# which has a status_code attribute. 200 means
226+
# success; 500 indicates a server-side error.
227+
228+
def retry(func):
229+
def retried_func(*args, **kwargs):
230+
MAX_TRIES = 3
231+
tries = 0
232+
while True:
233+
resp = func(*args, **kwargs)
234+
if resp.status_code == 500 and tries < MAX_TRIES:
235+
tries += 1
236+
continue
237+
break
238+
return resp
239+
return retried_func
240+
241+
This gives you an easy-to-use @retry decorator:
242+
243+
@retry
244+
def make_api_call():
245+
# ....
246+
247+
[/code]
248+
249+
## Boosting your career
250+
251+
Writing decorators isn’t easy at first. It’s not rocket science, but takes
252+
enough effort to learn, and to grok the nuances involved, that many developers
253+
will never go to the trouble to master it. And that works to your advantage.
254+
When you become the person on your team who learns to write decorators well,
255+
and write decorators that solve real problems, other developers will use them.
256+
Because once the hard work of writing them is done, decorators are so easy to
257+
use. This can **massively** magnify the positive impact of the code you write.
258+
And it just might make you a hero, too.
259+
260+
As I’ve traveled far and wide, training hundreds of working software engineers
261+
to use Python more effectively, teams have consistently reported writing
262+
decorators to be one of the most valuable and important tools they’ve learned
263+
in my advanced Python programming workshops. And that’s why it’s a key part of
264+
the upcoming [Python: Beyond the Basics](http://www.oreilly.com/online-courses
265+
/python-beyond-basics.html?intcmp=il-prog-olreg-article-
266+
oltrain_5_reasons_you_need_to_learn_to_write_python_decorators_inline) online
267+
course on May 25th and 26th, 2016.
268+
269+
No matter how you learn to write decorators, you can be excited about what
270+
you’ll be able to do with them, and how it will—no joke—change the way you
271+
write Python code forever!
272+
273+
Article image: Dragons (source: [Pixabay](https://pixabay.com/en/dragons-
274+
china-thailand-ornament-1124668/)).
275+
276+
[![Aaron Maxwell](https://d3tdunqjn7n0wj.cloudfront.net/360x360/aaron-maxwell-
277+
400x400-ac6d3f8dbbe679f53678b05d8ba70368.jpg)](https://www.oreilly.com/people/
278+
27097813-9a87-49f9-9fe3-84144509ace3)
279+
280+
## [Aaron
281+
Maxwell](https://www.oreilly.com/people/27097813-9a87-49f9-9fe3-84144509ace3)
282+
283+
Aaron Maxwell is the author of Advanced Python: A Not-For-Beginners Guide, and
284+
editor of the Advanced Python Newsletter. After a decade building the
285+
infrastructure and code for different Silicon Valley startups using a variety
286+
of languages—but mainly Python—he now travels widely to bring the most
287+
powerful secrets and best practices to Python developers around the world. He
288+
has started offering select online trainings, enabling students to benefit and
289+
learn at a fraction of the normal cost.
290+
291+
* * *
292+
293+
Video play
294+
295+
[![Ada Lovelace Day cake](https://d3tdunqjn7n0wj.cloudfront.net/360x240/ada-
296+
lovelace-cake-crop-
297+
e327b863e8879e00e3622f98706f2da3.jpg)](https://www.oreilly.com/ideas/looking-
298+
back-looking-ahead-ada-lovelace-day-founder-suw-charman-anderson)
299+
300+
[Software Engineering](https://www.oreilly.com/topics/software-engineering)
301+
302+
## [Looking back and looking ahead with Ada Lovelace Day's
303+
founder](https://www.oreilly.com/ideas/looking-back-looking-ahead-ada-
304+
lovelace-day-founder-suw-charman-anderson)
305+
306+
By [Mac Slocum](https://www.oreilly.com/people/0d2c1-mac-slocum)
307+
308+
Suw Charman-Anderson, founder of Ada Lovelace Day, explains why she started
309+
the day and why it's caught on.
310+
311+
[![Ada Lovelace portrait](https://d3tdunqjn7n0wj.cloudfront.net/360x240
312+
/ada_lovelace_portrait-crop-
313+
bbebd19ecc2a9d13093af94d1337ea90.jpg)](https://www.oreilly.com/ideas/ada-
314+
lovelace-an-indirect-and-reciprocal-influence)
315+
316+
[Software Engineering](https://www.oreilly.com/topics/software-engineering)
317+
318+
## [Ada Lovelace, an indirect and reciprocal
319+
influence](https://www.oreilly.com/ideas/ada-lovelace-an-indirect-and-
320+
reciprocal-influence)
321+
322+
By [Amy Jollymore](https://www.oreilly.com/people/amy-jollymore)
323+
324+
Celebrating women in technology and the curious mind of Ada Lovelace
325+
326+
[![Diagram for the computation of Bernoulli
327+
numbers](https://d3tdunqjn7n0wj.cloudfront.net/360x240
328+
/diagram_for_the_computation_of_bernoulli_numbers-crop-
329+
c5bd32cf467cdc1ad1f6985ef050f1f7.jpg)](https://www.oreilly.com/ideas
330+
/celebrating-ada-lovelace-day)
331+
332+
[Software Engineering](https://www.oreilly.com/topics/software-engineering)
333+
334+
## [Celebrating Ada Lovelace Day](https://www.oreilly.com/ideas/celebrating-
335+
ada-lovelace-day)
336+
337+
By [Suzanne Axtell](https://www.oreilly.com/people/6e5fe-suzanne-axtell)
338+
339+
The O'Reilly community shares stories of inspiring women in tech. Who inspired
340+
you?
341+
342+
[![Chains and gears](https://d3tdunqjn7n0wj.cloudfront.net/360x240
343+
/five_shouts-
344+
45a016ae78432673ef9980ed931d408f.jpg)](https://www.oreilly.com/ideas/the-five-
345+
shouts-of-good-programmers)
346+
347+
[Software Engineering](https://www.oreilly.com/topics/software-engineering)
348+
349+
## [The five shouts of good programmers](https://www.oreilly.com/ideas/the-
350+
five-shouts-of-good-programmers)
351+
352+
By [Abraham Marin-Perez](https://www.oreilly.com/people/99e91f20-69c9-4c42
353+
-bacf-198ffd26915c)
354+
355+
A set of reactions to the most common programming scenarios that tend to turn
356+
software projects sour.
357+
358+
### About Us
359+
360+
* [Our Company](http://oreilly.com/about/)
361+
* [Work with Us](http://oreilly.com/work-with-us.html)
362+
* [Customer Service](http://shop.oreilly.com/category/customer-service.do)
363+
* [Contact Us](http://shop.oreilly.com/category/customer-service.do)
364+
365+
### Site Map
366+
367+
* [Ideas](https://www.oreilly.com/ideas)
368+
* [Learning](https://www.oreilly.com/learning)
369+
* [Topics](https://www.oreilly.com/topics)
370+
* [All](https://www.oreilly.com/all)
371+
372+
* [ facebook ](http://fb.co/OReilly)
373+
* [ twitter ](http://twitter.com/oreillymedia)
374+
* [ youtube-large ](https://www.youtube.com/user/OreillyMedia)
375+
* [ google ](https://plus.google.com/+oreillymedia)
376+
* [ linkedin ](https://www.linkedin.com/company/o%27reilly-media)
377+
378+
[ ](https://www.oreilly.com/)
379+
380+
(C) 2016 O'Reilly Media, Inc. All trademarks and registered trademarks
381+
appearing on oreilly.com are the property of their respective owners.
382+
383+
384+
[Terms of Service](http://oreilly.com/terms/)[Privacy
385+
Policy](http://oreilly.com/privacy.html)[Editorial
386+
Independence](http://www.oreilly.com/about/editorial_independence.html)
387+
388+
![Animal](https://d3ebicv0uqgr7t.cloudfront.net/images/tarsier.png)
389+

0 commit comments

Comments
 (0)