目录
函数是第一类对象
在Python中,函数的行为类似于任何其他对象,例如int或list。这意味着您可以将函数用作其他函数的参数,将函数存储为字典值,或从另一个函数返回函数。这就产生了许多强大的函数使用方法。
def square(x):
"""Square of x."""
return x*x
def cube(x):
"""Cube of x."""
return x*x*x
将函数保存到字典中
# create a dictionary of functions
funcs = {
'square': square,
'cube': cube,
}
x = 2
print square(x)
print cube(x)
for func in sorted(funcs):
print func, funcs[func](x)
# output
4
8
cube 8
square 4
有些数据类型,如字符串和元组,不能直接修改,称为不可变。整数或浮点数等原子变量总是不可变的。其他数据类型,如列表和字典,可以直接修改,称为可变数据类型。将可变变量作为函数参数传递可能会产生不同的结果,这取决于函数内部对变量所做的操作。
高阶函数 Higher-order functions
使用另一个函数作为输入参数或返回函数(HOF)的函数称为高阶函数。最常见的例子是map
和filter
。
map
函数将一个函数应用于集合的每个成员
map(square, range(5))
#output
[0, 1, 4, 9, 16]
filter
函数将判断应用于集合的每个成员,只保留判断为真的那些成员。
def is_even(x):
return x%2 == 0
filter(is_even, range(5))
# output
[0, 2, 4]
reduce函数使用二进制运算符一次合并两个项来计算
def my_add(x, y):
return x + y
# 通过reduce函数也可以实现同意的结果
reduce(my_add, [1,2,3,4,5])
# output 15
# 自定义函数也可以是HOFs
def custom_sum(xs, transform):
"""计算通过转化后的xs的和."""
return sum(map(transform, xs))
xs = range(5)
print custom_sum(xs, square)
# output 30
print custom_sum(xs, cube)
# output 100
# 直接返回函数
def make_logger(target):
def logger(data):
with open(target, 'a') as f:
f.write(data + '\n')
return logger
foo_logger = make_logger('foo.txt')
foo_logger('Hello')
foo_logger('World')
匿名函数 Anonymous functions
当使用函数风格时,通常需要创建一些小的特定函数,这些函数执行有限的任务,作为HOF的输入,例如map
或 filter
。在这种情况下,这些函数通常被写成匿名函数或lambda函数。如果您发现很难理解lambda函数在做什么,那么可能应该将其重写为常规函数。
# 使用标准函数
def square(x):
return x*x
print map(square, range(5))
# output
[0, 1, 4, 9, 16]
# 使用匿名函数
print(map(lambda x: x*x, range(5))
# 这个函数在做什么
s1 = reduce(lambda x, y: x+y, map(lambda x: x**2, range(1,10)))
print(s1)
s2 = sum(x**2 for x in range(1,10))
# output都是285
纯函数 Pure functions
如果函数没有任何副作用,并且不依赖于全局变量,那么它们就是纯函数。纯函数类似于数学函数——每次给出相同的输入时,都会返回相同的输出。这对于减少bug和并行编程非常有用,因为每个函数调用都独立于任何其他函数调用,因此可以进行简单的并行化。
def pure(xs):
"""Make a new list and return that."""
xs = [x*2 for x in xs]
return xs
xs = range(5)
print("xs =", xs)
print(pure(xs))
print("xs =", xs)
# output
xs = [0, 1, 2, 3, 4]
[0, 2, 4, 6, 8]
xs = [0, 1, 2, 3, 4]
# 这里定义一个“不纯”的函数
def impure(xs):
for i, x in enumerate(xs):
xs[i] = x*2
return xs
xs = range(5)
print("xs =", xs)
print(impure(xs))
print("xs =", xs)
# output
xs = [0, 1, 2, 3, 4]
[0, 2, 4, 6, 8]
# note here
xs = [0, 2, 4, 6, 8]
# Note that mutable functions are created upon function declaration, not use.
# This gives rise to a common source of beginner errors.
def f1(x, y=[]):
"""不要将空列表或其他可变结构作为默认值"""
y.append(x)
return sum(y)
print(f1(10)) # 10
print(f1(10)) # 20
print(f1(10, y =[1,2])) # 13
# Here is the correct Python idiom
def f2(x, y=None):
"""Check if y is None - if so make it a list."""
if y is None:
y = []
y.append(x)
return sum(y)
print(f2(10)) # 10
print (f2(10)) # 10
print (f2(10, y =[1,2])) # 13
递归函数Recursion function
递归函数是一个调用自身的函数。递归函数是算法开发中分而治之范式divide-and-conquer
的非常有用的例子,是有限差分方程的直接表达式。然而,它们的计算效率很低,在Python中使用它们在实践中非常罕见。递归函数通常有一组基本情况,其中答案是显而易见的,可以立即返回,还有一组递归情况,它们被分成更小的部分,每个部分都被赋予递归调用的同一个函数。举几个例子可以更清楚地说明这一点。
# The factorial function is perhaps the simplest classic example of recursion.
def fact(n):
"""n的阶乘."""
# base case
if n==0:
return 1
# recursive case
else:
return n * fact(n-1)
print([fact(n) for n in range(10)])
# output
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
# The Fibonacci sequence is another classic recursion example
# 斐波那契序列是另一个经典的递归例子
def fib1(n):
"""Fib with recursion."""
# base case
if n==0 or n==1:
return 1
# recurssive caae
else:
return fib1(n-1) + fib1(n-2)
print([fib1(i) for i in range(10)])
# output
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
# In Python, a more efficient version that does not use recursion is
#在Python中,不使用递归的更高效版本是
def fib2(n):
"""Fib without recursion."""
a, b = 0, 1
for i in range(1, n+1):
a, b = b, a+b
return b
print([fib2(i) for i in range(10)])
# output
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
# Note that the recursive version is much slower than the non-recursive version
# 请注意,递归版本比非递归版本慢得多
%timeit fib1(20)
%timeit fib2(20)
# this is because it makes many duplicate function calls
# Note duplicate calls to fib(2) and fib(1) below
# fib(4) -> fib(3), fib(2)
# fib(3) -> fib(2), fib(1)
# fib(2) -> fib(1), fib(0)
# fib(1) -> 1
# fib(0) -> 1
#output
100 loops, best of 3: 5.64 ms per loop
100000 loops, best of 3: 2.87 µs per loop
def almost_quick_sort(xs):
"""Almost a quick sort."""
# base case
if xs == []:
return xs
# recursive case
else:
pivot = xs[0]
less_than = [x for x in xs[1:] if x <= pivot]
more_than = [x for x in xs[1:] if x > pivot]
return almost_quick_sort(less_than) + [pivot] + almost_quick_sort(more_than)
xs = [3,1,4,1,5,9,2,6,5,3,5,9]
print(almost_quick_sort(xs))
[1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9, 9]
迭代器 Iterators
迭代器表示数值流。因为一次只消耗一个值,所以它们使用的内存非常少。使用迭代器对于处理太大而无法放入RAM的数据集非常有用。
Iterators can be created from sequences with the built-in function iter()
xs = [1,2,3]
x_iter = iter(xs)
print x_iter.next() # 1
print x_iter.next() # 2
print x_iter.next() # 3
print x_iter.next() # 报错
# Most commonly, iterators are used (automatically) within a for loop
# which terminates when it encouters a StopIteration exception
x_iter = iter(xs)
for x in x_iter:
print (x)
生成器 Generators
# Functions containing the 'yield' keyword return iterators
# After yielding, the function retains its previous state
def count_down(n):
for i in range(n, 0, -1):
yield i
counter = count_down(10)
print(counter.next())
print(counter.next())
for count in counter:
print (count)
10
9
8 7 6 5 4 3 2 1
#还可以使用“生成器表达式”创建迭代器
#其编码类似于列表生成器,但带有括号
#代替方括号
xs1 = [x*x for x in range(5)]
print (xs1)
# output
[0, 1, 4, 9, 16]
xs2 = (x*x for x in range(5))
print xs2
# output
<generator object <genexpr> at 0x1130d09b0>
for x in xs2:
print(x)
0 1 4 9 16
#许多内置Python函数返回迭代器
#包括文件处理程序
#因此,使用下面的习惯用法,您可以逐行处理1TB的文件
#在你的笔记本电脑上没有任何问题
#在Pyhton 3中,map和filter返回iterators,而不是list
for line in open('foo.txt'):
print(line)
foo.txt
这个是前面保存的文件。
Hello
World
Hello
World
Hello
World
Hello
World
生成器和推导式 Generators and comprehensions
print((x for x in range(10)))
print([x for x in range(10)])
print({x for x in range(10)})
print({x: x for x in range(10)})
# output
<generator object <genexpr> at 0x0000013FC931A2E0>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}
实用程序-枚举、zip和三元if-else运算符 Utilites - enumerate, zip and the ternary if-else operator
两个有用的函数和一个不同寻常的运算符。
#在许多编程语言中,循环使用索引。
#这在Python中是可能的,但使用枚举函数更为惯用。
# using and index in a loop
xs = [1,2,3,4]
for i in range(len(xs)):
print(i, xs[i])
#output
0 1
1 2
2 3
3 4
# using enumerate
for i, x in enumerate(xs):
print(i, x)
#output
0 1
1 2
2 3
3 4
#当需要迭代多个列表中匹配的元素时,zip非常有用
# 当最短列表用尽时,zip停止
xs = [1, 2, 3, 4]
ys = [10, 20, 30, 40]
zs = ['a', 'b', 'c', 'd', 'e']
for x, y, z in zip(xs, ys, zs):
print (x, y, z)
1 10 a
2 20 b
3 30 c
4 40 d
对于列表理解,三元if-else运算符有时非常有用
[x**2 if x%2 == 0 else x**3 for x in range(10)]
# output
[0, 1, 4, 27, 16, 125, 36, 343, 64, 729]
装饰器 Decorators
装饰器是一种HOF,它接受一个函数并返回一个包装函数,该函数提供了额外的有用属性。
Examples:
- logging
- profiling
- Just-In-Time (JIT) compilation
# Here is a simple decorator to time an arbitrary function
def func_timer(func):
"""Times how long the function took."""
def f(*args, **kwargs):
import time
start = time.time()
results = func(*args, **kwargs)
print "Elapsed: %.2fs" % (time.time() - start)
return results
return f
# There is a special shorthand notation for decorating functions
@func_timer
def sleepy(msg, sleep=1.0):
"""Delays a while before answering."""
import time
time.sleep(sleep)
print msg
sleepy("Hello", 1.5)
Hello
Elapsed: 1.50s
The itertools
module
这为使用迭代器提供了许多基本函数。permuations
置换和combinations
组合生成器对于模拟可能特别有用,而groupby生成器对于数据分析非常有用。
from itertools import cycle, groupby, islice, permutations, combinations
print list(islice(cycle('abcd'), 0, 10))
# output
['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b']
# 根据字符串长度分组
animals = sorted(['pig', 'cow', 'giraffe', 'elephant',
'dog', 'cat', 'hippo', 'lion', 'tiger'], key=len)
for k, g in groupby(animals, key=len):
print k, list(g)
# output
3 ['pig', 'cow', 'dog', 'cat']
4 ['lion']
5 ['hippo', 'tiger']
7 ['giraffe']
8 ['elephant']
print [''.join(p) for p in permutations('abc')]
# output
['abc', 'acb', 'bac', 'bca', 'cab', 'cba']
print [list(c) for c in combinations([1,2,3,4], r=2)]
#output
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
翻译自 https://people.duke.edu/~ccc14/sta-663/FunctionsSolutions.html