您的位置:首页 > 编程语言 > Python开发

Python函数式编程

2017-07-14 11:31 218 查看
把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。

def add(x,y,f):
return f(x)+f(y)
print(add(-5,6,abs))


map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

#map
def f(x):
return x*x
print(list(map(f,range(10)))) #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

print(list(map(str,range(10)))) #['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']


reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

#reduce
from functools import reduce
def add(x,y):
return x+y

print(reduce(add,range(10))) #45

def fn(x,y):
return 10*x+y
print(reduce(fn,range(10)))#123456789

#str2int
def str2int(s):
def fn(x,y):
return 10*x+y
def char2num(s):
return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]
return(reduce(fn,map(char2num,s)))

print(str2int('3425556'))  #3425556

#将英文单词规范化:首字母大写,其余小写
L1=['adam','LISA','barT']
def stad(s):
temp=s[0].upper()+s[1:].lower()
return temp

L2=list(map(stad,L1))
print(L2)  #['Adam', 'Lisa', 'Bart']

#求乘积
def prod(L):
def mul(x,y):
return x*x
return reduce(mul,L3)

L3=[3,5,7,9]
print('3 * 5 * 7 * 9 =',prod(L3)) #3 * 5 * 7 * 9 = 6561

#将字符串转换为float
def str2float(s):
def char2num(s):
return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]
def findpoint(s):
n=0;
for c in s:
if (c=='.'):
break
else:
n=n+1
return n
def fn(x,y):#计算小数点之前的位数
return 10*x+y
def gn(x,y):#计算小数点之后的位数
return 0.1*x+y
point=findpoint(s)
zhen=reduce(fn,map(char2num,list(s[0:point])))
fen=0.1*reduce(gn,map(char2num,list(s[-1:point:-1])))#此处注意要乘以0.1
return zhen+fen
print(str2float('123.456'))  #123.456

#将字符串转换为float 先计算没有小数点的结果,再根据小数点的位置除以相应的数据
def str2float(s):
def char2num(s):
return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]
def findpoint(s):
n=0;
for c in s:
if (c=='.'):
break
else:
n=n+1
return n
def fn(x,y):#计算小数点之前的位数
return 10*x+y
point=findpoint(s)
return reduce(fn,map(char2num,list(s[0:point])+list(s[point+1:])))*pow(10,-point)#将两个list相连只需用+即可

print(str2float('123.456')) #123.456


filter()接收一个函数和一个序列,把传入的函数依次作用于每个元素,然后只保留使函数返回值是False的元素。

#filter
#filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。
def is_odd(n):
return n%2==1

print(list(filter(is_odd,range(16))))#将所有偶数过滤掉   [1, 3, 5, 7, 9, 11, 13, 15]

#删除序列中的空字符串
def not_empty(s):
return s and s.strip()  #strip函数没有参数时默认删掉字符串中的空字符
print(list(filter(not_empty,['A',' ','B',None,'C',' ']))) #['A', 'B', 'C']

#找出所有的素数
def _odd_iter():#生成器,奇数的无限序列
n=1
while True:
n=n+2
yield n

def _not_divisible(n):#筛选函数
return lambda x :x%n>0

def primes():
yield 2
it=_odd_iter()# 初始序列
while True:
n=next(it)# 返回序列的第一个数
yield n
it=filter(_not_divisible(n),it)# 构造新序列
# 打印1000以内的素数:
for n in primes():
if n < 1000:
print(n)
else:
break

#找出所有回文数
def is_palindrome(n):
s=list(str(n))
s2=s[::-1]
n=0
for i in range(len(s)):
if (s[i]==s2[i]):
n=n+1
return n==len(s)
def is_palindrome2(n):  #将n转化成str,与逆转后的str比较是否相等
return str(n) == str(n)[::-1]

output=filter(is_palindrome,range(1,1000))
print(list(output))
output=filter(is_palindrome2,range(1,1000))
print(list(output))
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191, 202, 2
#12, 222, 232, 242, 252, 262, 272, 282, 292, 303, 313, 323, 333, 343, 353, 363, 373, 383, 393, 404, 414, 424, 434, 444, 4
#54, 464, 474, 484, 494, 505, 515, 525, 535, 545, 555, 565, 575, 585, 595, 606, 616, 626, 636, 646, 656, 666, 676, 686, 6
#96, 707, 717, 727, 737, 747, 757, 767, 777, 787, 797, 808, 818, 828, 838, 848, 858, 868, 878, 888, 898, 909, 919, 929, 9
#39, 949, 959, 969, 979, 989, 999]


sorted()函数是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序,要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True

#sorted
print(sorted([36, 5, -12, 9, -21], key=abs)) #[5, 9, -12, -21, 36]
print(sorted(['bob', 'about', 'Zoo', 'Credit'])) #['Credit', 'Zoo', 'about', 'bob']
print(sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower))  #['about', 'bob', 'Credit', 'Zoo']

#按照姓名排序
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
return t[0]
L2=sorted(L,key=by_name)
print(L,'\n',L2)#[('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)] [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]
#按照成绩排序
def by_score(t):
return t[1]
L3=sorted(L,key=by_score,reverse=True) #[('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]
print(L,'\n',L3)

L4=sorted(L,key=by_score) # [('Bart', 66), ('Bob', 75), ('Lisa', 88), ('Adam', 92)]
print(L,'\n',L4)


高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

#返回函数
def count():
fs=[]
for i in range(1,4):
def f():
return i*i
fs.append(f) #此处虽然i在每次循环的值都不同,但是因为没有立刻执行函数,所以i的值没有固定,会随着循环而每次都不同
return fs
f1,f2,f3=count()
print(f1(),f2(),f3())#此时调用函数count,执行f函数,i=3,结果均为9

def count2():
def f(i):
def g():
return i*i
return g
fs=[]
for i in range(1,4):
fs.append(f(i))#立刻用不同的i调用函数f,返回值不同
return fs
f1,f2,f3=count2()
print(f1(),f2(),f3())  #1 4 9


关键字lambda表示匿名函数,冒号前面的x表示函数参数。

匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。

用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数

#匿名函数
def build(*args):
def f():
sum=0
for i in args:
sum=sum+i*i
return sum
return f

def build2(x,y):
return lambda:x*x+y*y

f1=build(2,3)
f2=build2(2,3)
print(f1(),f2()) #13 13

#使用lambda,x 从 0 迭代到 4 的时候每次都会先赋值给 n;所以 返回的"闭包"中参数n 是绑定的,不会因为 x 的变化而变化
squares = []
for x in range(5):
squares.append(lambda n=x: n*2)

print(squares[2]())

#使用之前的返回函数,达到与上述相同的目的
squares2 = []
def f(x):
def g():
return x*2
return g
for x in range(5):
squares2.append(f(x))
print(squares2[2]())

"""以下三种结果相同"""
def build(x, y):
return lambda: x * x + y * y
x = build(3, 6)
print(x())

def build():
return lambda x, y: x * x + y * y
y = build()
print(y(3, 6))

z = lambda x, y: x * x + y * y
print(z(3, 6))


要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)

#装饰器Decorator
import functools
def now():
print('2017-7-14')
def log(func):
@functools.wraps(func)
def wrapper(*args,**kw):
print('call %s():' % func.__name__)#打印日志
return func(*args,**kw)#调用函数
return wrapper

def log2(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator

@log#相当于执行now = log(now),now变量指向了新的函数,调用时会在log()中返回wrapper()函数
def now():
print('2017-7-14')
print(now.__name__)  #now
print(now())  #call_now()  2017-7-14

@log2('execute')# now = log('execute')(now),首先执行log('execute'),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数
def now2():
print('10:21')
print(now2.__name__) #now2
print(now2()) #execute now2():  10:21

#用一个@log的decorator,使它既支持带参数,也支持不带参数
def log(text):
def real_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
if isinstance(text,str): display=text
else:display=''
print('begin call',display)
func()
print('end call')
return wrapper
if isinstance(text,str):
return real_decorator
else:
return real_decorator(text)
@log('ext')
def f():
print('call f()') #begin call ext   call f()   end call

@log
def f1():
print('call f1()')
print(f(),'\n',f1())  #begin call   call f1()   end call


偏函数:functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单

#偏函数
print(int('1243'))
print(int('1243',base=6)) #315 将6进制的‘1243’转化成十进制的int

def int6(x,base=6):
return int(x,base)
print(int6('1243'))  #315

def int2(x, base=2):#另外定义一个有默认参数的函数,省的每次都设置base的值
return int(x, base) #此处不用return int(x, base=2)是为了代码灵活性,调用int2时也可以传入其他参数
print(int2('10001010')) #138
print(int2('10001010',6))#280158  调用int2时也可以传入其他参数

import functools
int2=functools.partial(int,base=2)#定义偏函数
print(int2('10001010')) #138
#但也可以在函数调用时传入其他值桶上面自己定义的int2
#偏函数的参数包括函数对象,*args和**kw三个,默认情况下kw = { 'base': 2 }
print(int2('1000000', base=10)) #1000000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: