python 比较6的
函数式编程
**:首先 先要知道 变量可以指向函数,然后这个变量就是函数了,就可以当做函数被使用。
高阶函数
*:函数的参数可以接收变量,也可以接收 函数,凡是接收函数的函数,叫做高阶函数
例1:def add(x,y,f):
return f(x)+f(y)
add(10,5,abs)
例2 : import math
def add(x, y, f):
return f(x) + f(y)
print add(25, 9, math.sqrt)
**
map()
**高阶函数:接收一个函数f和一个list;返回一个新的list(原来的list中每一个element都被f操作一遍)
例 def f(x):
return x*x
return map(f,[1,2,3,4,5])
reduce()
高阶函数:同样接收一个f和list,与map不同,f(x,y)必须接收两个参数
f将list中每2个element一次操作一遍,,先操作第一个和第二个,然后操作结果,与第三个操作,还可以设置个初始值reduce(f,list,num)使list中第一个数先和num操作然后结果与第二个操作
例子 def f(x,y)
return x+y
reduce(f,[1,2,3,4,5],100)
## #
## ##
filter() ##
高阶函数:同样接收一个f和list,f对每一个元素进行判断 返回的 true 或者false 根据结果 筛掉不符合的元素
例子1 def is_odd(x):
return x % 2 == 1
然后,利用filter()过滤掉偶数:
filter(is_odd, [1, 4, 6, 7, 9, 12, 17])
例子2 def is_not_empty(s):
return s and len(s.strip()) > 0
filter(is_not_empty, ['test', None, '', 'str', ' ', 'END'])
sorted(f,list)
高阶函数:用来排序
f(x,y)
想要让x在y前面 return -1
x在y后面 return 1
x和y相等 return 0
例子1
def reversed_cmp(x, y):
if x > y:
return -1
if x < y:
return 1
return 0
sorted([1,2,3,6,3,7],f)
例子2
def cmp_ignore_case(s1, s2):
u1 = s1.upper()
u2 = s2.upper()
if u1 < u2:
return -1
if u1 > u2:
return 1
return 0
print sorted(['bob', 'about', 'Zoo', 'Credit'], cmp_ignore_case)
返回函数 ##
函数不光能接收函数,还能返回函数,
def calc_sum(lst):
def lazy_sum():
return sum(lst)
return lazy_sum
calc_sum 返回的是lazy_sum
print calc_sum([1,2,3,4,5,6])
我们会发现打印的是个lazy_sum函数地址而不是结果
如果想执行结果
我们需要 执行 返回的函数;
f=calc_sum([1,2,3,4,5,6])
print f(),其应用可以让结果不立即出来,
看下一个内容 闭包
闭包
讲函数定义到函数里面,目的是使里面的函数(内函数)不被外面访问,
但是当内函数用到外函数的变量作为参数的时候 ,我们成为闭包。
切记一定不要用 外面函数中变化的 变量来作为参数如
例:def outer():
fs[]
for i in range(1,4)
def inner():
fs.append i*i
return i*i
return fs
f1,f2,f3= outer()
print f1(),f2(),f3()
返回结果为 9,9,9
(这里用三个函数接收因为fs存的是三个方法而不是值)
不信你自己print fs或者累不下面的代码
def count():
fs = []
for i in range(1, 4):
fs.append(i*i)
return fs
f=count()
print f
如果你不想返回三个9 那么 找一个先的参数接收
def count():
fs=[]
for i in range(1,4)
def f(y):
def lo():
y=i
return y*y
return lo
fs.append(f(i))
return fs
就会返回1,4,9
def f(y):
def lo():
y=i
return y*
return lo
注意这个
其实返回的是[f1(),f2(),f3()]
期间我看的是廖雪峰的教程,想法有些抽象。慢慢看半天就差不多了
匿名函数
python对匿名函数有一些支持,单只支持单行的表达式格式是
lambda: 参数 单行函数
匿名函数有个限制,就是只能有一个表达式,不写return,返回值就是该表达式的结果。
例sorted([1,2,3,4,5],lamdba x,y: -cmp(x,y))
[5,4,3,2,1]
map(lamdba x:x*x,[1,2,3,4,5])
装饰器
类似于java 中的拦截器,不过python能非常轻松的完成,而且功能更加强大,如:给一个函数 日志,用高阶函数完成
def pre(f):
def g():
print 'call%s '%(f.__name__)
r=f()
return r
return g
然后用
l=pre(f)---->f=pre(f)去调用
python中省去了调用 直接写
@pre(f)
即可写日志!
**无参装饰器**: 装饰器要装饰不同函数,当函数参数不同,如果装饰器将 参数写固定, 就会出现编译错误
这时要借助 *args **kw将参数写可变
例子:同上,写日志:
def pre(f):
def fn(*args,**kw):
print 'call %s '%(f.__name__)
return f(*args,**kw)
return fn
import time
例子:在函数上打印使用时间
def performance(f):
def fn(*args,**kw):
t1=time.time()
r=f(*args,**kw)
t2=time.time()
print 'call %s() in %fs'%(f.__name__,(t2-t1))
return r
return fn
@performance
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10)
用参装饰器 ##
当你想写的日志不是固定的call f.name, 想针对不同的函数设置不同的级别 这时候需要给装饰器更完善一下
def log(index):
def wraps(f):
def g(*args,**kw):
print'[%s]call %s '%{index,f.__name__}
return f(*args,**fw)
return g
return wrap
@log
fercial()
打印调用函数所用时间
import time
def performance(unit):
def pre_decorator(f):
def log(*args,**kw):
time1 =time.time()
r=f(*args,**kw)
time2 = time.time()
if unit =='ms':
t=(time2-time1)*1000
else:
t=(time2-time1)
print 'call %s() in %f %s'%(f.__name__,t,unit)
return r
return log
return pre_decorator
@performance('s')
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10)
进一步优化装饰器
当再使用装饰器的时候打印的name,doc都是装饰器里的属性
有一些依靠name来操作的函数就会出现错误,为了避免
应该使装饰器里的函数的name,doc等于被装饰函数
def perform(f):
def wraps(*args,**kw):
wraps.__name__=f.__name__
wraps.__doc__=f.__doc__
return f(*args,**kw)
return wraps
@perform
def fercial(n):
print n
print fercial.__name__
python有个简单的:functools中的wraps方法
import functools
def log(f):
@functools.wraps(f)
def wrapper(*args, **kw):
print 'call...'
return f(*args, **kw)
return wrapper
偏函数
当一个函数有很多参数时,调用者就需要提供多个参数。如果减少参数个数,就可以简化调用者的负担。
比如,int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:
int(‘12345’)
12345
但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做 N 进制的转换:int(‘12345’, base=8)
5349
int(‘12345’, 16)
74565
假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去:
def int2(x, base=2):
return int(x, base)
这样,我们转换二进制就非常方便了:
int2(‘1000000’)
64
int2(‘1010101’)
85
functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2:import functools
int2 = functools.partial(int, base=2)
int2(‘1000000’)
64
int2(‘1010101’)
85
所以,functools.partial可以把一个参数多的函数变成一个参数少的新函数,少的参数需要在创建时指定默认值,这样,新函数调用的难度就降低了。