Python之路(第七篇)Python作用域、匿名函数、函数式编程、map函数、filter函数、reduce函数
一、作用域
return 可以返回任意值
例子
- def test1():
- print("test1")
- def test():
- print("test")
- return test1
- res = test()
- print(res)
输出结果
- test
- <function test1 at 0x021F5C90>
分析:这里print(res)输出的是test1函数在内存中的地址,return也是可以返回的
,加上括号就可以运行函数了
例子2
- name = "pony"
- def test1():
- name = "nicholas"
- def inner():
- name = "jack"
- print(name)
- return inner
- res = test1()
- print(res)
- res()
输出结果
- <function test1.<locals>.inner at 0x02195C48>
- jack
分析:
test1函数返回了inner函数的内存地址,并被赋值给res,所以最后在res后加上括号就可以直接执行,注意这里执行的是inner函数,打印name选择的是局部变量name ="jack",而非选择调用执行的res()所在的name = "pony"
例子3
- def foo():
- name = 'jack'
- def bar():
- name = 'pony'
- print(name)
- def tt():
- print(name)
- return tt
- return bar
- r1 = foo() #返回的是bar函数的内存地址
- r2 = r1() #执行了bar函数,返回了tt函数的内存地址
- r3 = r2() #执行了tt函数,输出 pony
输出结果
- pony
- pony
分析:r1是执行foo函数,最后得到的是bar函数的内存地址,r2是执行了bar函数,返回了tt函数的内存地址,执行了tt函数,输出 pony。
这里也可以直接这样写
foo()()()
foo()是r1,foo()()是r2,foo()()()就是r3.
二、匿名函数
1、lambda
例子
lambda x:x+1
这里的x相当于自定义函数的形参,x+1相当于return的返回值
def calc(x)
return x+1
这个自定义函数和lambda x:x+1是等价的
lambda函数一般用直接是处理加减法、乘法、加字符串
例子
- def calc(x):
- return x+1
- res = calc(10)
- print(res)
- print(calc)
输出结果
- 11
- <function calc at 0x02245C48>
例子2
- print(lambda x:x+1)
输出结果
- <function <lambda> at 0x021B5C48>
分析:这里是lambda函数在内存中的地址,和calc函数是一样的(未执行,即未加括号的情况下 )
调用lambda()
例子
- func = lambda x:x+1
- res = func(10)
- print(res)
输出
- 11
分析:调用lambda函数需要将lambda函数赋值给一个变量,执行时用变量名加()带参数执行,这里括号内的参数类似自定义函数的实参,通过调用传给形参。
例子3
- print(list(filter(lambda x:x if x % 2 == 0 else "" ,range(10))))
输出结果
- [2, 4, 6, 8]
分析:lambda可以用if -else语句,但是不能单独用if语句,必须if-else语句一起写
2、lambda返回多个值
例子
- func = lambda x,y,z:x + y + z
- res = func(10,11,12)
- print(res)
- #或者这样写
- print(func(10,11,12))
例子2
- func = lambda x,y,z:(x + 1 ,y + 1,z +1)
- res = func(10,11,12)
- print(res)
- #或者直接这样写
- print(func(10,11,12))
输出结果
- (11, 12, 13)
- (11, 12, 13)
分析:这里返回多个值需要用括号和逗号
三、函数式编程
1、编程的三种方法论
面向过程编程、函数式编程、面向对象编程
面向过程:
定义
是一种以过程为中心的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。
简单的就是把任务分为一个一个的步骤,一步一步的执行。
函数式编程:
定义
在计算机科学里,函数式编程是一种编程范式,它将计算描述为表达式求值并避免了状态和数据改变。函数式编程里面的“函数”指的是数学函数。
对于任何一个编程函数,需要满足下面3个条件,即可转换成纯数学函数。
每个函数必须包含输入参数(作为自变量)
每个函数必须有返回值(作为因变量)
无论何时,给定参数调用函数时,返回值必须一致。
面向对象编程
定义
面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。
2、函数式编程递归调用
高阶函数的定义
(1)函数名可以当做参数传递
(2)返回值可以是参数
例子
- def foo(n): #n=bar
- print(n)
- def bar(name):
- print('my name is %s' %name)
- foo(bar)
- foo(bar("nicholas"))
输出结果
- <function bar at 0x02225C48>
- my name is nicholas
- None
分析:这里的foo(bar),其中的bar是作为一个函数当做参数传入foo(),bar是一个内存地址。foo(bar("nicholas"))中,bar("nicholas")执行函数,先输出my name is nicholas,然后执行foo函数,由于bar函数没有return出数值,所以执行foo()输出None。
3、尾调用优化(尾递归优化)
尾调用:在函数的最后一步调用另外一个函数(最后一行不一定是函数的最后一步)
例子
- def bar(n):
- return n
- def foo(x):
- return bar(x)
这里的return bar()就是函数的最后一步。
例子
- def test(x):
- if x > 1:
- return True
- elif x == 1:
- return False
- else:
- return False
- test(1)
分析:这里的最后一步是执行elif x ==1下面的 return False语句。
尾递归与非尾递归
非尾递归
- def cal(seq):
- if len(seq) == 1:
- return seq[0]
- head , *tail = seq
- return head + cal(tail)
- print(cal(range(100)))
尾递归
- def cal(l):
- print(l)
- if len(l) == 1:
- return l[0]
- frist,second,*args = l
- l[0] = frist + second
- l.pop(1)
- return cal(l)
- x = cal([i for i in range(10)])
- print(x)
3、 map()函数
map() 会根据提供的函数对指定序列做映射。
map(function, iterable, ...)
function -- 函数,有两个参数
iterable -- 一个或多个序列
它有两个参数,第一个参数为某个函数,第二个为可迭代对象。
例子
需求,将li1 = [1,3,4,5,7,10] 的每个元素变成自己的平方。
用for循环解决
- li1 = [1,3,4,5,7,10]
- li = []
- for i in li1:
- li.append(i ** 2)
- res = li
- print(res)
升级需求,处理多个列表,将列表的的每个元素变成自己的平方。
- li1 = [1,3,4,5,7,10]
- def map_test():
- li = []
- for i in li1:
- li.append(i ** 2)
- return li
- res = map_test(li1)
- print(res)
继续升级需求,将原列表的每个元素平方,组成新的列表
- li1 = [1,3,4,5,7,10]
- def pow_test(n):
- return n ** 2
- def map_test(fun,array):
- li = []
- for i in array:
- res = fun(i)
- li.append(res)
- return li
- res1 = map_test(pow_test,li1)
- print(res1)
分析:这里的map_test函数的参数fun传入的是一个函数,即这个map_test函数是高阶函数,在map_test函数里调用其他函数,对第二个传入的对象进行处理。两个这里map_test()、pow_test()加在一起实现的功能就是map()函数的作用。
这里可以用map()函数处理
- li1 = [1,3,4,5,7,10]
- res1 = list(map(lambda x:x**2,li1))
- print(res1)
分析:map()函数的第一个参数是一个函数,即匿名函数,这里不需要加括号执行,只是代表对一个参数的处理方式,map()第二个参数是待处理的可迭代对象。
map()函数直接处理结果是一个map()函数的内存地址,是一个可迭代类型,需要加list转换为列表。
这里map()函数的第一个参数不一定非要写lambda函数,也可以写自定义的函数名。
例子
- def reduce_one(n):
- return n - 1
- li1 = [1,3,4,5,7,10]
- res1 = list(map(reduce_one,li1))
- print(res1)
输出结果
- [0, 2, 3, 4, 6, 9]
关于map()函数输出的结果处理
例子
用for 循环处理结果
- li1 = [1,3,4,5,7,10]
- res1 = map(lambda x:x**2,li1)
- for i in res1:
- print(i)
- print(res1)
输出结果
- 1
- 9
- 16
- 25
- 49
- 100
- <map object at 0x02185790>
直接用map函数
- li1 = [1,3,4,5,7,10]
- res = list(map(lambda x:x**2,li1))
- print("map处理结果是",res)
输出结果
- map处理结果是 [1, 9, 16, 25, 49, 100]
分析:这里可以看出map()函数直接输出的结果是一个可迭代对象,加上list可以将其转换为列表。
4、filter()函数
filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
filter:过滤,滤除
例子
,要从一个list [1, 4, 6, 7, 9, 12, 17]中删除偶数,保留奇数
用自定义函数和for循环解决
- li = [1, 4, 6, 7, 9, 12, 17]
- li1 = []
- def filter_old(n):
- if n % 2 == 1:
- li1.append(n)
- def test():
- for i in li:
- res = filter_old(i)
- test()
- print(li1)
输出
- [1, 7, 9, 17]
这里也可以直接用filter函数解决。
- li = [1, 4, 6, 7, 9, 12, 17]
- def filter_old(n):
- if n % 2 == 1:
- return n
- res = list(filter(filter_old,li))
- print(res)
输出结果
- [1, 7, 9, 17]
或者更精简一些
- li = [1, 4, 6, 7, 9, 12, 17]
- res = list(filter(lambda n:n %2 ==1,li))
- print(res)
输出结果
- [1, 7, 9, 17]
分析:这里的lambda函数是一个函数处理逻辑,最终是返回了符合 n %2 ==1条件的n
这里与map函数一样,也需要List将其转换为列表。
例子
- li = [1, 4, 6, 7, 9, 12, 17]
- res = list(filter(lambda n:not n %2 ==1,li))
- print(res)
分析:这里的lambda也可以加not。
例子
- li = [
- {"name":"jack","age":53},
- {"name":"pony","age":46},
- {"name":"charles","age":53},
- {"name":"richard","age":44}
- ]
- v = list(filter(lambda p:p["age"]<45,li))
- print(v)
输出结果
- [{'name': 'richard', 'age': 44}]
分析:这里lambda返回的就是符合条件的元素p,遍历序列中的每个元素,判断每个元素得到布尔值,如果是True则留下来。
5、reduce()函数
reduce()在python2中可以直接用
在python3中需要添加模块导入
from functools import reduce
reduce()的使用方法形如reduce(f(x),Itera).对,它的形式和map()函数一样。不过参数f(x)必须有两个参数。reduce()函数作用是:把结果继续和序列的下一个元素做累积计算。
例子
需求将列表[1,2,3,4,5,6]所有元素加起来。
用for循环解决
- li = [1,2,3,4,5,6]
- sum = 0
- for i in li:
- sum = sum + i
- print(sum)
需求2,求列表li = [1,2,3,4,5,6]每个元素相乘最终结果
用自定义函数处理
- li = [1,2,3,4,5,6]
- def test(x,y):
- return x*y
- def test1(func,array):
- res = array.pop(0)
- #这里表示列表的第一个元素
- #pop()删除某个值,并可以获取当前删除的值
- for i in array:
- res = func(res,i)
- #这里是传入的相乘的结果和下一个元素,初始值为res = array[0]。
- return res
- v = test1(test,li)
- print(v)
输出结果
- 720
分析:这里是自定义了2个函数,通过函数中调用另一个函数处理。这里也可以直接用reduce()函数处理。
- from functools import reduce
- li = [1,2,3,4,5,6]
- v = reduce(lambda x,y:x*y,li)
- print(v)
输出
- 720
分析:注意这里不再使用list方法。
reduce 有 三个参数
function 有两个参数的函数, 必需参数
sequence tuple ,list ,dictionary, string等可迭代对象,必需参数
initial 初始值, 可选参数
如果没有初始值init,直接执行将第二个参数可迭代对象通过第一个参数func进行处理。
如果有初始值Init,则首先进行初始值和待传入的第二个参数的第一个元素通过func进行处理,之后这个累计值再和第二个元素进行累计。
例子
- from functools import reduce
- li = [1,2,3,10]
- v = reduce(lambda x,y:x*y,li,10)
- print(v)
输出结果
- 600
分析:这里首先将初始值10 * 1 得到10,然后用累计值10 *2 得到20,然后20*3,以此类推,最后得到600.
6、map()、filter()、reduce()小结
map()
处理序列中的每个元素,得到的结果是一个‘列表’(内存地址),该‘列表’元素个数及位置与原来一样
filter()
filter遍历序列中的每个元素,判断每个元素得到布尔值,如果是True则留下来
reduce()
处理一个序列,然后把序列进行合并操作
Python之路(第七篇)Python作用域、匿名函数、函数式编程、map函数、filter函数、reduce函数的更多相关文章
- Python之路(第五篇) Python基本数据类型集合、格式化、函数
一.变量总结 1.1 变量定义 记录某种状态或者数值,并用某个名称代表这个数值或状态. 1.2 变量在内存中的表现形式 Python 中一切皆为对象,数字是对象,列表是对象,函数也是对象,任何东西都是 ...
- 【Python之路】特别篇--Python装饰器
前情提要 1. 作用域 在python中,函数会创建一个新的作用域.python开发者可能会说函数有自己的命名空间,差不多一个意思.这意味着在函数内部碰到一个变量的时候函数会优先在自己的命名空间里面去 ...
- Python之路(第八篇)Python内置函数、zip()、max()、min()
一.python内置函数 abs() 求绝对值 例子 print(abs(-2)) all() 把序列中每一个元素做布尔运算,如果全部都是true,就返回true, 但是如果是空字符串.空列表也返回t ...
- 【Python之路】特别篇--Python面向对象(初级篇)
概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 面向过程编程最易被初学 ...
- Python之路(第六篇)Python全局变量与局部变量、函数多层嵌套、函数递归
一.局部变量与全局变量 1.在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量.全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序. 全局变量没有任何缩进,在任何位置都可 ...
- python学习-day15:函数作用域、匿名函数、函数式编程、map、filter、reduce函数、内置函数r
---恢复内容开始--- 一.全局变量与局部变量 在子程序中定义的变量称为局部变量, 在程序的一开始定义的变量称为全局变量. 全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序.当全局变量与 ...
- python学习-day16:函数作用域、匿名函数、函数式编程、map、filter、reduce函数、内置函数r
一.作用域 作用域在定义函数时就已经固定住了,不会随着调用位置的改变而改变 二.匿名函数 lambda:正常和其他函数进行配合使用.正常无需把匿名函数赋值给一个变量. f=lambda x:x*x p ...
- Python的map、filter、reduce函数 [转]
1. map函数func作用于给定序列的每个元素,并用一个列表来提供返回值. map函数python实现代码: def map(func,seq): mapped_seq = [] fo ...
- 【Python之路】第九篇--Python基础之线程、进程和协程
进程与线程之间的关系 线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除.线程可与属于同一进程的其它线程共享进程所拥有的全 ...
随机推荐
- Shell 处理文件名中包含空格的文件
最近在学Gradle, 使用git clone 命令下载了一些资料,但是文件名含有空格,看上去不是很舒服,因此想到用shell脚本对其进行批处理,去掉文件名中的空格,注意这里是把所有的空格全去掉 gi ...
- HTTP 协议 详解
一.HTTP简介 1.HTTP协议,即超文本传输协议(Hypertext transfer protocol).是一种详细规定了浏览器和万维网(WWW = World Wide Web)服务器之间互相 ...
- xlwt使用
xlwt引入xlwt,import xlwt 新建工作簿,xlsx = xlwt.Workbook( encoding="utf-8" ),参数:设置编码为utf-8 添加工作表, ...
- DB2 57016报错的解决办法(表状态不正常,导致表无法操作)
新建了一张表,删除了一列,然后执行insert的时候,报错 57016,解释为:因为表不活动. 1.执行db2 "load query table <tabname>" ...
- PHPActiveRecord 学习一
#连接数据库 <?phprequire_once dirname(__FILE__) . '/../../ActiveRecord.php'; // initialize ActiveRecor ...
- phpstorm添加站点
1.在界面上快捷键 ctrl+alt+s 或打开File->settings 2.找到Deployment 设置完后确定即可使用.
- sqoop2问题解决
sqoop:000> show version --serverException has occurred during processing command Exception: org.a ...
- TZOJ 3710 修路问题(最小差值生成树kruskal或者LCT)
描述 xxx国“山头乡”有n个村子,政府准备修建乡村公路,由于地形复杂,有些乡村之间可能无法修筑公路,因此政府经过仔细的考察,终于得到了所有可能的修路费用数据.并将其公布于众,广泛征求村民的修路意见. ...
- 第五章 Inheritance继承
[继承] Java不支持多重继承 - 每个子类只有一个超类. 不是将成员变量声明为静态,更好的做法是将University实例化为对象,然后使用该对象访问其成员,如下所示: [抽象类] 可以包含或者不 ...
- swift4.2 打印所有系统字体
func showAllFonts(){ let familyNames = UIFont.familyNames var index:Int = 0 for familyName in family ...