Article Outline

# 函数工具

## 迭代器（Iterator）

``````string = "this is a string."
list = ['item 1', 'item 2', 3, 5]
set = (1, 2, 3, 4, 5)
for c in string:
print(c, end=', ')
print()
for L in list:
print(L, end=', ')
print()
for s in set:
print(s, end=', ')
print()``````
``````t, h, i, s,  , i, s,  , a,  , s, t, r, i, n, g, .,
item 1, item 2, 3, 5,
1, 2, 3, 4, 5,``````

``````i = iter("Python")
print(type(i))
s = iter((1, 2, 3, 4, 5))
print(type(s))
L = iter(['item 1', 'item 2', 3, 5])
print(type(L))``````
``````str_iterator
tuple_iterator
list_iterator``````

``````i = iter("Python")
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
# next(i) 前面已经到 'n' 了，再调用就会有 StopIteration 错误提示。``````
``````'P'
'y'
't'
'h'
'o'
'n'``````

`i` 这个迭代器里一共有 6 个元素，所以，`next(i)` 在被调用 6 次之后，就不能再被调用了，一旦再被调用，就会触发 StopIteration 错误。

``````class Counter(object):
def __init__(self, start, stop):
self.current = start
self.stop = stop
def __iter__(self):
return self
def __next__(self):
if self.current > self.stop:
raise StopIteration
else:
c = self.current
self.current += 1
return c

c = Counter(11, 20)
print(next(c))
print(next(c))
print(next(c))
for c in Counter(101, 105):
print(c, sep=', ')
print(type(Counter))``````
``````11
12
13
101
102
103
104
105

type``````

``````def __iter__(self):
return self``````

``````class Counter(object):
def __init__(self, start, stop):
self.current = start
self.stop = stop
def __iter__(self):
return self
def __next__(self):
if self.current > self.stop:
raise StopIteration
else:
c = self.current
self.current += 1
return c

for c in Counter(101, 103):
print(c, sep=', ')

c = Counter(201, 203)
while True:
try:
print(next(c), sep=', ')
except StopIteration:
break``````
``````101
102
103
201
202
203``````

## 生成器（Generator）

``````def counter(start, stop):
while start <= stop:
yield start
start += 1
for i in counter(101, 105):
print(i)``````
``````101
102
103
104
105``````

``````even = (e for e in range(10) if not e % 2)
# odd = (o for o in range(10) if o % 2)
print(even)
for e in even:
print(e)``````
``````<generator object <genexpr> at 0x107cc0048>
0
2
4
6
8``````

``````# even = (e for e in range(10) if not e % 2)
odd = [o for o in range(10) if o % 2]
print(odd)
for o in odd:
print(o)``````
``````[1, 3, 5, 7, 9]
1
3
5
7
9``````
``````# even = (e for e in range(10) if not e % 2)
odd = {o for o in range(10) if o % 2}
print(odd)
for o in odd:
print(o)``````
``````{1, 3, 5, 7, 9}
1
3
5
7
9``````

``````sum_of_even = sum(e for e in range(10) if not e % 2)
print(sum_of_even)``````
``20``

``````def a_func():
def b_func():
pass
def c_func():
pass
def d_func():
pass
b_func()
return True``````

``````def a_func():
def b_func():
print("Hi, I'm b_func!")
print("Hi, I'm a_func!")
a_func()``````
``Hi, I'm a_func!``
``````def a_func():
def b_func():
print("Hi, I'm b_func!")
print("Hi, I'm a_func!")
b_func()
a_func()``````
``````Hi, I'm a_func!
Hi, I'm b_func!``````

``````def a_func():
def b_func():
print("Hi, I'm b_func!")
print("Hi, I'm a_func!")
return b_func()
a_func()``````
``````Hi, I'm a_func!
Hi, I'm b_func!``````

``````def a_func():
def b_func():
print("Hi, I'm b_func!")
print("Hi, I'm a_func!")
return b_func
print(a_func())``````
``````Hi, I'm a_func!
<function __main__.a_func.<locals>.b_func()>``````

## 装饰器（Decorator）

### 函数也是对象

``````def a_decorator(func):
def wrapper():
print('We can do sth. before a func is called...')
func()
print('... and we can do sth. after it is called...')
return wrapper()

def a_func():
print("Hi, I'm a_func!")

a_func()
a_decorator(a_func)``````
``````Hi, I'm a_func!
We can do sth. before a func is called...
Hi, I'm a_func!
... and we can do sth. after it is called...``````

``````def a_decorator(func):
def wrapper():
print('We can do sth. before a func is called...')
func()
print('... and we can do sth. after it is called...')
return wrapper  #

def a_func():
print("Hi, I'm a_func!")

a_func()
print(a_decorator(a_func))``````
``````Hi, I'm a_func!
<function __main__.a_decorator.<locals>.wrapper()>``````

### 装饰器操作符

``````def a_decorator(func):
def wrapper():
print('We can do sth. before calling a_func...')
func()
print('... and we can do sth. after it was called...')
return wrapper

@a_decorator
def a_func():
print("Hi, I'm a_func!")

a_func()``````
``````We can do sth. before calling a_func...
Hi, I'm a_func!
... and we can do sth. after it was called...``````

—— 被 `@` 调用的函数，叫做 “装饰器”（Decorator），比如，以上代码中的 `a_decorator(func)`

``````@a_decorator
def a_func():
...``````

``````def a_func():
...
a_func = a_decorator(a_func)``````

### 装饰器的用途

Decorator 最常用的场景是什么呢？最常用的场景就是用来改变其它函数的行为。

``````def an_output():
return 'The quick brown fox jumps over the lazy dog.'
print(an_output())``````
``The quick brown fox jumps over the lazy dog.``
``````def uppercase(func):
def wrapper():
original_result = func()
modified_restult = original_result.upper()
return modified_restult
return wrapper

@uppercase
def an_output():
return 'The quick brown fox jumps over the lazy dog.'
print(an_output())``````
``THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.``

``````def uppercase(func):
def wrapper():
original_result = func()
modified_restult = original_result.upper()
return modified_restult
return wrapper
def strong(func):
def wrapper():
original_result = func()
modified_restult = '<strong>'+original_result+'</strong>'
return modified_restult
return wrapper

@strong
@uppercase
def an_output():
return 'The quick brown fox jumps over the lazy dog.'
print(an_output())``````
``<strong>THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.</strong>``

``````@uppercase
@strong
def an_output():
...``````

### 装饰带有参数函数

``````def a_decorator(func):
def wrapper(*args, **kwargs):
return original_result
# ...
return wrapper``````

``````def say_hi(greeting, name=None):
return greeting + '! ' + name + '.'

print(say_hi('Hello', 'Jack'))``````
``Hello! Jack.``

``````def trace(func):
def wrapper(*args, **kwargs):
print(f"Trace: You've called a function: {func.__name__}(),",
f"with args: {args}; kwargs: {kwargs}")

original_result = func(*args, **kwargs)
print(f"Trace: {func.__name__}{args} returned: {original_result}")
return original_result
return wrapper

@trace
def say_hi(greeting, name=None):
return greeting + '! ' + name + '.'

print(say_hi('Hello', name = 'Jack'))``````
``````Trace: You've called a function: say_hi(), with args: ('Hello',); kwargs: {'name': 'Jack'}
Trace: say_hi('Hello',) returned: Hello! Jack.
Hello! Jack.``````

https://wiki.python.org/moin/PythonDecoratorLibrary

### 学会装饰器究竟有多重要？

Oreilly.com 上有篇文章，《5 reasons you need to learn to write Python decorators》中，其中的第五条竟然是：Boosting your career!

Writing decorators isn't easy at first. It's not rocket science, but takes enough effort to learn, and to grok the nuances involved, that many developers will never go to the trouble to master it. And that works to your advantage. When you become the person on your team who learns to write decorators well, and write decorators that solve real problems, other developers will use them. Because once the hard work of writing them is done, decorators are so easy to use. This can massively magnify the positive impact of the code you write. And it just might make you a hero, too.

As I've traveled far and wide, training hundreds of working software engineers to use Python more effectively, teams have consistently reported writing decorators to be one of the most valuable and important tools they've learned in my advanced Python programming workshops.