#python进阶学习笔记1(廖雪峰课程)
##高阶函数
python和Js很像,支持将函数作为变量输入到参数的参数里面去,此时将函数作为参数的函数称之为高阶函数
变量也是可以指向函数的,例如:1
2
3fun=abs()
fun(-10)
一般存在一下几个常用的高阶函数,将list和function作为参数输入处理:
map函数的例子1
2
3
4
5def (x):
return x*x
print map(f,[range(1,10)])
#输出的结果是[x for x in range(1,82) if math.sqrt(x) in range(1,10)]
reduce函数1
2
3
4def (x,y):
return x+y
reduce(f,range(1,10)[::2])
该函数输出的结果是:1
2
3
4
5先计算头两个元素:f(1, 3),结果为4;
再把结果和第3个元素计算:f(4, 5),结果为9;
再把结果和第4个元素计算:f(9, 7),结果为16;
再把结果和第5个元素计算:f(16, 9),结果为25;
由于没有更多的元素了,计算结束,返回结果25。
reduce函数还可以指定计算的初始值:1
2reduce(f,range(1,10)[::2],100)
#输出的结果:125
filter()函数:filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。1
2
3
4
5def is_odd(x):
return x %2 ==1
filter(is_odd,[1,4,6,7,9,12,17])
#输出结果 [1,7,9,17]
利用filter(),可以完成很多有用的功能,例如,删除 None 或者空字符串:1
2
3
4
5
6
7
8
9
10
11
12def is_not_empty(s):
return s and len(s.strip())>0
filter(is_not_empty, ['test', None, '', 'str', ' ', 'END'])
#输出结果 :['test', 'str', 'END']
#注意: s.strip(rm) 删除 s 字符串中开头、结尾处的 rm 序列的字符。
#当rm为空时,默认删除空白符(包括'n', 'r', 't', ' '),如下:
a = ' 123'
a.strip()
#结果是 '123'
自定义排序函数
sorted()也是一个高阶函数,它可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。
因此,如果我们要实现倒序排序,只需要编写一个reversed_cmp函数:1
2
3
4
5
6
7
8
9
10def reversed_cmp(x, y):
if x > y:
return -1
if x < y:
return 1
return 0
# 实现倒序排序
sorted([36, 5, 12, 9, 21], reversed_cmp)
#输出结果:[36, 21, 12, 9, 5]
python中的函数作为变量看待
python最骚的就是和JS一样将函数作为变量看待,一个函数的返回值是可以返回一个函数!!!,因为python将函数作为变量看待
Python的函数不但可以返回int、str、list、dict等数据类型,还可以返回函数!
例如,定义一个函数 f(),我们让它返回一个函数 g,可以这样写:1
2
3
4
5
6
7
8def ():
print 'call f()'
#定义一个g函数
def g():
print 'call g()'
#函数g作为返回,注意返回的是函数名!!!
return g
执行的结果:1
2
3
4
5
6>>> x = f() # 调用f()
call f()...
>>> x # 变量x是f()返回的函数:
>>> x() # x指向函数,因此可以调用
call g()... # 调用x()就是执行g()函数定义的代码
注意返回函数的时候是返回函数名,不是调用函数1
2
3
4
5
6
7def myabs():
return abs
#返回的是函数名
def myabs1(x):
return abs(x)
#返回的是值!!!
python中的闭包操作
和Js一模一样,在一个函数里面定义另一个函数,在这个函数里面存在定义函数的外部变量封装起来1
2
3
4
5def ():
a='local'
def g():
print a
return g
这里看起来函数g中的变量a是外界看不到的变量,廖雪峰老师的进阶课程中对闭包的解释:
例子:1
2
3
4def calc_sum(lst):
def lazy_sum():
return sum(lst)
return lazy_sum
注意: 发现没法把 lazy_sum 移到 calc_sum 的外部,因为它引用了 calc_sum 的参数 lst。
像这种内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)。
闭包的特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。
一个闭包错误的例子:1
2
3
4
5
6
7
8
9
10# 希望一次返回3个函数,分别计算1x1,2x2,3x3:
def count():
fs = []
for i in range(1, 4):
def ():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果全部都是 9(请自己动手验证)。
原因就是当count()函数返回了3个函数时,这3个函数所引用的变量 i 的值已经变成了3。由于f1、f2、f3并没有被调用,所以,此时他们并未计算 i*i,当 f1 被调用时:1
2>>> f1()
9 # 因为f1现在才计算i*i,但现在i的值已经变为3
因此,返回函数不要引用任何循环变量,或者后续会发生变化的变量。
我的理解
python在执行对应的程序的时候才去读取对应的i值,此时的for已经结束,因此i一直都是3,修改代码:1
2
3
4
5
6
7
8
9
10
11def count():
fs=[]
for i in range(1,4):
def f(x=i):
return x*x
fs.append(f)
return fs
f1,f2,f3=count()
print f1(),f2(),f3()
#输出理想的结果 1,4,9
Python中的闭包其实还有一个问题,外层函数的变量和里层函数的变量重名,但是这个变量不是总的函数的外部变量,这就会出bug:1
2
3
4
5
6
7
8
9
10def fun1():
count=0
def func():
count+=1
print 'Now count is',count
return func
test=fun1()
test()
#直接会报错哦
解决方案加入关键词 nonlocal(python 3支持)1
2
3
4
5
6
7
8
9
10
11def fun1():
count=0
def func():
nonlocal count+=1
print 'Now count is',count
return func
test=fun1()
test()
test()
test()
python中的匿名函数
套路和JS很像直接在参数传入的过程中定义一个简单的函数
但是JS是有关键字function的,而python中的关键词是lambda!!!
简单示例函数:1
2map(lambda x:x*x,range(1,10))
#输出结果[1,4,9,16,25,36,49,64,84]
匿名函数的实体定义类似:1
2def f(x):
return x*x
关键字lambda 表示匿名函数,冒号前面的 x 表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不写return,返回值就是该表达式的结果。
这也是python比JS的不足,JS的匿名函数没有那么多限制就是直接定义,但是python的灵活就在于函数对象的使用,例如:1
2sorted([1, 3, 9, 5, 0], lambda x,y: -cmp(x,y))
#结果:[9, 5, 3, 1, 0]
返回函数的时候,也可以返回匿名函数:1
2
3
4
5>>> myabs = lambda x: -x if x < 0 else x
>>> myabs(-1)
1
>>> myabs(1)
1