【Python】【函数式编程】
#【练习】
请定义一个函数quadratic(a, b, c)
,接收3个参数,返回一元二次方程:
ax2 + bx + c = 0
的两个解。
提示:计算平方根可以调用math.sqrt()
函数:
>>> import math
>>> math.sqrt(2)
1.4142135623730951
# -*- coding: utf-8 -*- import math def quadratic(a, b, c):
# 测试:
print('quadratic(2, 3, 1) =', quadratic(2, 3, 1))
print('quadratic(1, 3, -4) =', quadratic(1, 3, -4)) if quadratic(2, 3, 1) != (-0.5, -1.0):
print('测试失败')
elif quadratic(1, 3, -4) != (1.0, -4.0):
print('测试失败')
else:
print('测试成功')
import math
# 解答
def quadratic(a,b,c):
for i in (a,b,c):
if not isinstance(i,(int,float)):
raise TypeError('bad operand type')
if a == 0:
x = -c/b
return x
delta = b*b - 4*a*c
if delta < 0:
print ('此方程无解')
elif delta > 0:
x1 = (-b+math.sqrt(delta))/(2*a)
x2 = (-b-math.sqrt(delta))/(2*a)
return x1,x2
elif delta == 0:
x1=x2= -b/(2*a)
return x1,x2
print (quadratic(1,4,1))
print (quadratic(0,2,-1))
print (quadratic('a',4,1))
# 结果
(-0.2679491924311228, -3.732050807568877)
0.5
Traceback (most recent call last):
File "/Users/suren/PycharmProjects/liaoxuefeng_test1/test_one.py", line 22, in <module>
print (quadratic('a',4,1))
File "/Users/suren/PycharmProjects/liaoxuefeng_test1/test_one.py", line 6, in quadratic
raise TypeError('bad operand type')
TypeError: bad operand type
#【练习】2
利用切片操作,实现一个trim()函数,去除字符串首尾的空格,注意不要调用str的strip()
方法:
【解答】
def trim(string):
if not isinstance(string,(str,)):
raise TypeError('arg error')
#左判断
while ' ' == string[0]:
string = string[1:]
#右判断
while ' ' == string[-1]:
string = string[:-1]
return string
# 【【函数式编程】】
"""
函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。 而函数式编程(请注意多了一个“式”字)——Functional Programming,虽然也可以归结到面向过程的程序设计,但其思想更接近数学计算。 我们首先要搞明白计算机(Computer)和计算(Compute)的概念。 在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语言是最贴近计算机的语言。 而计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。 对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言;越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Lisp语言。 函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。 函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数! Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。
"""
#【高阶函数】 #变量可以指向函数
print (abs(-10))
print(abs) #<built-in function abs> def add(x,y,f):
return f(x) + f(y)
x = -5
y = 6
f = abs
print(add(x,y,f)) #11 # 【高阶函数】【map】
def f(x):
return x * x
r = map(f,[1,2,3,4,5])
print(list(r)) #[1, 4, 9, 16, 25]
print(r) #<map object at 0x1022454a8>
#一行代码就是
print(list(map(f,[1,2,3,4])))#[1, 4, 9, 16, 25] #【高阶函数】【reduce】
from functools import reduce
def add(x,y):
return x + y
r = reduce(add,[1,2,3,4])
print(r) #10
#当然,求和运算也可以用python内建函数sum,没必要动用reduce.
#但是,如果要把序列[1,3,5,7,9]变成整数13579,reduce就可以派上用场
from functools import reduce
def fn(x,y):
return 10 * x + y
print(reduce(fn,[1,3,5,7,9])) #13579 # str 转 int
from functools import reduce DIGITS = {"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"0":0} def str2int(s):
def fn(x,y):
return 10 * x + y
def char2num(ss):
return DIGITS[ss]
return reduce(fn,map(char2num,s))
print(str2int("13579")) #13579 # 还可以用lambda函数进一步简化
def str2int(s):
return reduce(lambda x,y:10 * x + y,map(lambda a: DIGITS[a],s))
print(str2int("2468")) #2468 # 练习1:利用map函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。
def nomalize(name):
return name.capitalize()
L1 = ["adam","LISA","barT"]
L2 = list(map(nomalize,L1))
print(L2) #['Adam', 'Lisa', 'Bart'] #练习2:python提供的sum()函数可接收一个list并求和。请编写一个prod()函数,可接收一个list并通过reduce求积
def prod(L):
return reduce(lambda x,y:x * y,L)
print('1*3*5*4=',prod([1,3,5,4]))
if prod([1,3,5,4]) == 60:
print("测试成功!")
else:
print("测试失败!")
'''
1*3*5*4= 60
测试成功!
'''
#练习3:利用map reduce编写str2float,把字符串"123.456"转成浮点数123.456
#方法1 我自己写的
from functools import reduce
def str2float1(s):
digits = {"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"0":0}
def fn(x,y):
return 10 * x + y
def char2num(s):
return digits[s]
return reduce(fn,map(char2num,s.split(".")[0])) + reduce(fn,map(char2num,s.split(".")[1]))/10**len(s.split(".")[1])
print('str2float1(\'123,456\')=',str2float1('123.456'))
if str2float1('123.456') == 123.456:
print('测试成功!')
else:
print('测试失败!')
'''
str2float1('123,456')= 123.456
测试成功!
''' # 方法2:网上的,比较简洁
from functools import reduce
def str2float2(s):
def fn(x,y):
return 10*x + y
n = s.index(".")
s1 = list(map(int,s[:n]))
s2 = list(map(int,s[n+1:]))
return reduce(fn,s1) + reduce(fn,s2)/10**len(s2)
print('str2float(\'789.123\')=',str2float2('789.123'))
if str2float2('789.1234') == 789.1234:
print('测试成功!')
else:
print('测试失败!')
'''
str2float('789.123')= 789.123
测试成功!
''' # 【高阶函数】【filter】
# and & or
print(0 or 1) #1
print(1 or 0) #1
print(False or True) #True
print(True or 0) #True
print(False or 0) #0
print('***********')
print(0 and 1) #0
print(1 and 3) #3
print(1 and 0) #0
print(True and False) #False
print(False and 7) #False
print(1 and 7) #7
print(None and None.strip())#None # 把一个序列中的空字符串删掉
def not_empty(s):
return s and s.strip()
print(list(filter(not_empty,['A','','B',None,'C',' ']))) #['A','B','C'] # 用filter求素数
'''
【分析】
计算素数的一个方法是埃氏筛法,它的算法理解起来非常简单:
首先,列出从2开始的所有自然数,构造一个序列:
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
取序列的第一个数2,它一定是素数,然后用2把序列的2的倍数筛掉:
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
取新序列的第一个数3,它一定是素数,然后用3把序列的3的倍数筛掉:
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
取新序列的第一个数5,然后用5把序列的5的倍数筛掉:
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
不断筛下去,就可以得到所有的素数。
'''
# 分三步。1 先构造一个从3开始的奇数数列 2 定义一个筛选函数 3 定义一个生成器,不断返回下一个素数
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) # 由于primes()也是一个无限序列,所以调用时需设置一个退出循环的条件:
for n in primes():
if n < 10:
print(n)
else:
break
'''
2
3
5
7
''' # 练习 回数指从左往右和从右往左都是一样的数。利用filter()筛选出 回数
output = list(filter(lambda n: str(n)[0:] == str(n)[::-1],range(1,100)))
print(output)
if output == [1,2,3,4,5,6,7,8,9,11,22,33,44,55,66,77,88,99]:
print('测试成功!')
else:
print('测试失败!') # 【高阶函数】【sorted】
print(sorted([36,5,-12,9,-21])) #[-21, -12, 5, 9, 36]
print(sorted([36,5,-12,9,-21],key=abs)) #[5, 9, -12, -21, 36]
print(sorted(['bob','about','Zoo','Credit'])) #['Credit', 'Zoo', 'about', 'bob'] 【备注】字符串排序,默认按照ASCII大小,由于大写字母在小写字母之前
#如果想忽略大小写
print(sorted(['bob','about','Zoo','Credit'],key=str.lower)) #['about', 'bob', 'Credit', 'Zoo']
#用大写函数同样适用
print(sorted(['bob','about','Zoo','Credit'],key=str.upper)) #['about', 'bob', 'Credit', 'Zoo']
#反向排序
print(sorted(['bob','about','Zoo','Credit'],key=str.upper,reverse=True))#['Zoo', 'Credit', 'bob', 'about'] # 练习:用一组tuple表示学生名字和成绩
L = [('Bob',75),('Adam',92),('Bart',66),('Lisa',88)]
#请用sorted对上述列表分别按照名字和成绩排序
def by_name(t):
return t[0].lower()
def by_score(t):
return t[1]
print('按照名字排序结果: ',sorted(L,key=by_name)) #按照名字排序结果: [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]
print('按照成绩排序结果: ',sorted(L,key=by_score)) #按照成绩排序结果: [('Bart', 66), ('Bob', 75), ('Lisa', 88), ('Adam', 92)] # 【【函数式编程】】【返回函数】
#函数作为返回值
#实现一个可变参数的求和。通常情况下,求和函数这样定义
def calc_sum(*args):
ax = 0
for n in args:
ax = ax + n
return ax
#但是,如果不需要立即求和,而是后面,根据需要再计算。可不直接返回求和结果,而是返回求和函数。
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
f = lazy_sum(1,3,5,7,9)
print(f) #<function lazy_sum.<locals>.sum at 0x101a5a048>
print(f()) #25
# 【注意】每次调用lazy_sum()时,都会返回一个新的函数,即使传入相同的参数
f1 = lazy_sum(1,3,5)
f2 = lazy_sum(1,3,5)
print(f1 == f2) #False f1() f2()调用结果互不影响 # 闭包
def count():
fs = []
for i in range(1,4):
def f():
return i * i
fs.append(f)
return fs
f1,f2,f3 = count()
print(f1())
print(f2())
print(f3())
'''
9
9
9
全部都是9,原因在于,返回的函数引用了变量i,但它并非立即执行。等到三个函数都返回时,它们引用的变量已经编程了3,因此最终结果是9。
'''
#【注意】返回闭包牢记,返回函数不要引用任何循环变量,或者后续会发生变化的变量
#如果一定要引用循环变量,可再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何修改,已绑定到函数参数的值不变。
def count2():
def f(j):
def g():
return j * j
return g
fs = []
for i in range(1,4):
fs.append(f(i))
return fs
f1,f2,f3 = count2()
print(f1())
print(f2())
print(f3()) '''
1
4
9
'''
# 方法内的变量,在方法帧未走完之前,一直有效 【备注】我也不知道这么形容对不对。。。只是我自己对此理解的一种方式。就像
import time
def now():
timeL = []
time1 = time.time()
time2 = time1 + 1000
time3 = time2 + 1000
timeL.append(time1)
timeL.append(time2)
timeL.append(time3)
def g(x):
return timeL[x]
return g
bb = now()
for i in range(0,3):
print(bb(i))
'''
1531637726.270685
1531638726.270685
1531639726.270685
''' #练习:利用闭包返回一个函数,每次调用它都会返回递增整数
#方法1
def createCounter():
a = [0]
def counter():
a[0] = a[0] + 1
return a[0]
return counter
createrA = createCounter()
print(createrA(),createrA(),createrA())
#方法2
a = 0
def createCounter2():
def counter():
global a
a = a + 1
return a
return counter
createrB = createCounter2()
print(createrB(),createrB(),createrB()) #【装饰器】
def now():
print('2018-07-15')
f = now
print(now.__name__) #now
print(f.__name__) #now # 两层嵌套
'''
现在,假设要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能
的方式,称之为"装饰器"(Decorator).
本质上,decorator就是一个返回函数的高阶函数。
'''
def log(func):
def wrapper(*args,**kwargs):
print('call %s():'%func.__name__)
return func(*args,**kwargs)
return wrapper
@log
def now():
print('2018-07-15')
now()
print(now.__name__)
'''
call now():
2018-07-15
wrapper
''' '''
把@log放到now()函数的定义处,相当于执行now = log(now),由于log()是一个decorator,返回一个函数,原来的now()函数仍然存在,只是
现在同名的now变量指向了新的函数,于是调用now()将执行新的函数
'''
#decorator本身需要传入参数。
def log(text):
def decorator(func):
def wrapper(*args,**kwargs):
print('%s %s():' % (text,func.__name__))
func(*args,**kwargs)
return wrapper
return decorator
@log('execute')
def now():
print('2018-07-15')
now()
#【解析】相当与定义now = log('execute')(now) #经过decorator装饰的函数,名字都会编程 wrapper ,为避免以来函数签名的的代码执行错误,不需要编写wrapper.__name__ = func.__name__,python内置的functools.wraps就是做这个的。所以,一个完整的decorator如下。
import functools def log(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
print('call %s():' % func.__name__)
return func(*args,**kwargs)
return wrapper #或者带参数的decorator
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
print('%s %s():' % (text,func.__name__))
return func(*args,**kwargs)
return wrapper
return decorator() #练习 设计一个decorator,可作用于任何函数上,并打印该函数的执行时间。
import time,functools
def printcalltime(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
start = time.time()
res = func(*args,**kwargs)
end = time.time()
print('%s execute time = %s ms' % (func.__name__,(end - start)*1000) )
return res
return wrapper @printcalltime
def print1():
time.sleep(1)
print (1) print1()
print(print1.__name__)
'''
1
print1 execute time = 1002.7890205383301 ms
print1
''' # 练习
'''
写出一个@log的decorator,使它既支持: @log
def f():
pass 又支持: @log('execute')
def f():
pass
'''
def log2(text):
if callable(text) == False:
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('execute %s for %s ' % (text,func.__name__))
return func(*args,**kwargs)
return wrapper
return decorator
else:
@functools.wraps(text)
def wrapper(*args,**kwargs):
return text(*args,**kwargs)
return wrapper
@log2
def now1():
print ("hello now1") @log2('too late')
def now2():
print ("hello now2") now1()
now2()
'''
hello now1
execute too late for now2
hello now2
''' # 【偏函数】
#int函数,默认是10进制。
print(int('12345')) #12345
#int函数还提供base参数,默认是10,如果传入,则按照参数的进制进行转换
print(int('12345',base=8)) #5349
print(int('12345',8)) #5349
print(int('11',base=2)) #3
#假设要大量转换二进制字符串,每次都传入int(x,base=2)太麻烦,于是想到定义一个int2()函数,默认把base=2传进去
def int2(x,base=2):
return int(x,base)
#functools.partial就是创建偏函数的,不需要自己定义int2()
import functools
int2 = functools.partial(int,base=2)
print(int2('100')) #4
print(int2('101')) #5
'''
创建偏函数时,实际上可以接收函数对象、*args和**kw这3个参数,当传入: int2 = functools.partial(int, base=2)
实际上固定了int()函数的关键字参数base,也就是: int2('10010')
相当于: kw = { 'base': 2 }
int('10010', **kw)
当传入: max2 = functools.partial(max, 10)
实际上会把10作为*args的一部分自动加到左边,也就是: max2(5, 6, 7)
相当于: args = (10, 5, 6, 7)
max(*args)
结果为10。
'''
【Python】【函数式编程】的更多相关文章
- Python函数式编程:从入门到走火入魔
一行代码显示"爱心" >>> print]+(y*-)**-(x**(y*<= ,)]),-,-)]) Python函数式编程:从入门到走火入魔 # @fi ...
- python函数式编程,列表生成式
1.python 中常见的集中存储数据的结构: 列表 集合 字典 元组 字符串 双队列 堆 其中最常见的就是列表,字典. 2.下面讲一些运用循环获取字典列表的元素 >>> dic={ ...
- (转)Python函数式编程——map()、reduce()
转自:http://www.jianshu.com/p/7fe3408e6048 1.map(func,seq1[,seq2...]) Python 函数式编程中的map()函数是将func作用于se ...
- python 函数式编程学习笔记
函数基础 一个函数就是将一些语句集合在一起的部件,它们能够不止一次地在程序中运行.函数的主要作用: 最大化的代码重用和最小化代码冗余 流程的分解 一般地,函数讲的流程是:告诉你怎样去做某事,而不是让你 ...
- python 函数式编程:高阶函数,map/reduce
python 函数式编程:高阶函数,map/reduce #函数式编程 #函数式编程一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数 #(一)高阶函数 f=abs f print ...
- Python函数式编程(进阶2)
转载请标明出处: http://www.cnblogs.com/why168888/p/6411915.html 本文出自:[Edwin博客园] Python函数式编程(进阶2) 1. python把 ...
- Python函数式编程——map()、reduce()
文章来源:http://www.pythoner.com/46.html 提起map和reduce想必大家并不陌生,Google公司2003年提出了一个名为MapReduce的编程模型[1],用于处理 ...
- python函数式编程之返回函数、匿名函数、装饰器、偏函数学习
python函数式编程之返回函数 高阶函数处理可以接受函数作为参数外,还可以把函数作为结果值返回. 函数作为返回值 def laxy_sum(*args): def sum(): ax = 0; fo ...
- Python函数式编程简介
参考原文 廖雪峰Python函数式编程 函数 函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程 ...
- Python 函数式编程 & Python中的高阶函数map reduce filter 和sorted
1. 函数式编程 1)概念 函数式编程是一种编程模型,他将计算机运算看做是数学中函数的计算,并且避免了状态以及变量的概念.wiki 我们知道,对象是面向对象的第一型,那么函数式编程也是一样,函数是函数 ...
随机推荐
- 设置 DNS,防止 DNS 污染,清除 DNS 缓存ipconfig /flushdns
设置 DNS,防止 DNS 污染选中“使用下面的 DNS 服务器地址”,“首选 DNS 服务器”中填写 8.8.8.8,“备用 DNS 服务器”中填写 8.8.4.4,然后点击“确定”按钮清除 DNS ...
- AWS免费云服务套餐申请步骤及常见问题
AWS免费云服务套餐申请步骤及常见问题 AWS免费使用套餐常见问题_AWS免费云服务套餐_-AWS云服务https://amazonaws-china.com/cn/free/faqs/ 什么是 AW ...
- js数组内数字按大小排序实现函数
正常冒泡排序: function evlabc(a) { //排序大小 var i = j = t = 0; for (i = 0; i < a.length; i++) { for (j = ...
- rgferg
dfgsdfg fdvgdsafg fgdfgdfg
- JustOj 2042: Dada的游戏
题目描述 Dada无聊时,喜欢做一个游戏,将很多钱分成若干堆排成一列,每堆钱数不固定,谁能找出每堆钱数严格递增的最长区间,谁就是人生赢家了.Dada可能脑子里的水还没干,她找不出来,你来帮她找找吧. ...
- Redhat 简单本地yum 配置
Redhat 简单本地yum 配置 一.将redhat 系统的镜像挂载到系统上 Vmware Workstion 环境下: [虚拟机设置]--[硬件]--[CD/DVD]--[使用ISO映像文件]-- ...
- P5015 标题统计
P5015 标题统计 ‘ ’ 不等于空格,空格是个字符 代码: #include<iostream> #include<cstdio> #include<cmath& ...
- python-数据分析与展示(Numpy、matplotlib、pandas)---1
笔记内容整理自mooc上北京理工大学嵩天老师python系列课程数据分析与展示,本人小白一枚,如有不对,多加指正 1.ndarray对象的属性 .ndim..shape..size(元素个数,不是占用 ...
- The Little Prince-12/02
The Little Prince-12/02 What moves me so deeply, about this little prince who is sleeping here, is h ...
- MySql与MariaDB由来与历程
MySQL数据库 MySQL数据库是一个关系型数据库管理系统,由瑞典MySQL AB公司开发.MySQL是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这 ...