Python基础复习函数篇
目录
1.猴子补丁
2. global和nonlocal关键字
3.迭代器和生成器
4.递归函数
5.高阶函数和lamdba函数
6.闭包
7.装饰器
1. 猴子补丁
猴子补丁主要用于在不修改已有代码情况下修改其功能或增加新功能的支持。
例如: 在使用第三方模块时,模块中的某些方法可能无法满足我们的开发需求。此时,我们可以在不修改这些方法代码的情况下,通过猴子补丁用一些
自己编写的新方法进行替代,从而实现一些新的功能。
如很多代码用到 import json,后来发现ujson性能更高,如果觉得把每个文件的import json 改成 import ujson as json成本较高,或者说想测试一下用ujson替换json是否符合预期,只需要在入口加上:
import json
import ujson
def monkey_patch_json():
json.__name__ = 'ujson'
json.dump = ujson.dumps
json.loads = ujson.loads
monkey_patch_json()
2. global和nonlocal关键字
在一个函数中使用global关键字,可以声明在该函数中使用的是全局变量
而非局部变量。
在一个函数中要修改全局变量,必须使用global声明。
在python中,函数的定义可以嵌套,即在一个函数的函数体中可以包含另一个函数的定义。
通过nonlocal关键字,可以使内层的函数直接使用外层函数中定义的变量。
例如:
def outer1(): # 不加nonlocal
x = 10 # 局部变量
def inner():
x = 20
print(x)
print(x) outer1()
输出结果:
20
10 def outer2(): # 加nonlocal
x = 10 # 局部变量
def inner():
nonlocal x = 20
print(x)
print(x) outer2()
输出结果:
20
20
3.迭代器和生成器
迭代器 Iterator
迭代器是访问可迭代对象的工具。迭代器有两个基本的方法:iter() 和 next()。
迭代器是指用iter(obj) 返回的对象(实例)。迭代器可以用next(it) 获取可迭代对象的数据。
iter(iterable) 从可迭代对象中返回一个迭代器,其中iterable必须是一个能提供一个迭代器的对象,如字符串,列表或元组对象都可用于创建迭代器。
next(iterator) 从迭代器iterator中获取下一个数据,如果无法获取下一行数据,则触发StopIteration异常
说明:
代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
用iter函数可以返回一个可迭代对象的迭代器
L = [2, 3, 5, 7]
it = iter(L) # it 绑定的是可迭代对象 L 提供的迭代器
print(next(it)) # 2 # 向迭代器要数据
print(next(it)) #
print(next(it)) #
print(next(it)) #
print(next(it)) # StopIteration异常 myit = iter(range(1, 10, 3)) # range也可以作为一个迭代器对象 1, 4, 7
print(next(myit)) #
print(next(myit)) #
print(next(myit)) #
print(next(myit)) # StopIteration异常 可用try捕获
迭代器对象也可以使用常规for语句进行遍历:
list=[1,2,3,4]
it = iter(list) # 创建迭代器对象
for x in it:
print (x, end=" ") 输出结果如下:
1 2 3 4
生成器 generator
含有yield语句的函数是生成器函数,此函数被调用将返回一个生成器对象,在生成器函数调用return会触发一个StopIteration异常(即生成结束)
生成器函数调用时返回的生成器是一次性的,当生成结束后将不再提供数据
yield 可翻译为产生或生成
yield 语句
语法:
yield 表达式
说明:
yield 用于
def 函数中,目的是将此函数作为生成器函数使用
yield 用来生成数据,提供迭代器 next(it) 函数使用
下面举例 自己用生成器实现python内建函数 filter
这个函数也可以加深对迭代器的理解:
def myfilter(fn, iterable):
it = iter(iterable) # 先拿到迭代器
while True:
try:
x = next(it) # 取值
if fn(x):
yield x
except StopIteration:
return # 生成结束 for x in myfilter(lambda y: y % 2 == 1, range(10)):
print(x) # 1 3 5 7 9
iter(可迭代对象) 用可迭代对象生成迭代器
next(iter(可迭代对象)) 从迭代器中取值
yield x 包含yield的函数即生成器函数
4. 递归函数
递归函数是指在一个函数内部通过调用自己来完成一个问题的求解
当我们在进行问题的分解时,发现分解之后待解决的子问题与原问题有着相同
的特性和解法,只是在问题规模上与原问题相比有所减小,此时,就可以设计递归
函数进行求解
比如,对于计算n!的问题,可以将其分解为: n! = n * (n – 1) .可见,分解后的子问题
(n - 1)! 与原问题的 n! 的计算方法完全一样,只是规模有所减少。
同样,(n - 1)! 这个子问题有可以进一步分解为(n-1) * (n-2)! 可以进一步分解为
(n - 2)(n - 3)! ... , 直到要计算 1! 时,直接返回1 .
def fac(n):
if n == 1: # 递归特性一:必须有一个明确的结束条件
return 1
else:
return n * fac(n-1) # 递归特性二:每次递归都是为了让问题规模变小,即找出函数的等价关系式 print(fac(5)) # 120 #递归特性三:递归层次过多会导致栈溢出,且效率不高
注意:
当问题规模较大时,递归调用会涉及到很多层的函数调用,一方面会由于栈操作影响程序运行速度,另一方面在Python中有栈的限制,
太多层的函数调用会引起栈溢出问题,如将 fac(5) 改成 fac(1000)则会报错。
在定义递归函数时,要先明确函数的功能,这样才能完成递归特性二的写法。
5.高阶函数和lamdba函数
高阶函数是指把函数作为参数的一种函数
其中注意 函数不仅可以赋给形参 ,也可以赋给变量。赋值后,既可以用变量名替代函数名完成函数调用,
此时变量储存的是函数的内存地址,通过()调用这个地址的内容,即函数。
lambda函数也称为匿名函数, 是一种不使用def定义函数的形式,其作用是能快速定义一个简短的函数
lambda函数的函数体只是一个表达式, 所以lambda函数通常只能实现比较简单的功能。
形式 :
lamdba[参数1[,参数2,...,参数n]] : 表达式
冒号后面的表达式的计算结果即为该lamdba函数的返回值。实例如下:
def FunAdd(f,x,y): # 定义函数FunAdd
return f(x) + f(y) # 用传给f的函数先对x和y分别处理后,再求和并返回
print(FunAdd(lambda x:x**2, 3, -5)) # 计算32 + (-5)2
print(FunAdd(lambda x:x**3,3,-5)) # 计算33 + (-5)3
也可以将lamdba函数赋值给一个变量,然后通过该变量去调用响应的lamdba函数。如:
fun = lamdba x:x**2 print(fun(3)) # 输出9
其他高阶函数
filter函数
filter(function or None, iterable) --> filter object
''' Return an iterator yielding those items of iterable for which function(item)
is true. If function is None, return the items that are true.'''
>>>list(filter(None,[1,2,0,True,False]))
>>>Out: [1, 2, True]
zip函数
zip(iter1 [,iter2 [...]]) --> zip object
| Return a zip object whose .__next__() method returns a tuple where
| the i-th element comes from the i-th iterable argument. The .__next__()
| method continues until the shortest iterable in the argument sequence
| is exhausted and then it raises StopIteration.
参数iterable为可迭代的对象,并且可以有多个参数。该函数返回一个以元组为元素的列表,其中第 i 个元组包含每个参数序列的第 i 个元素。返回的列表长度被截断为最短的参数序列的长度。只有一个序列参数时,它返回一个1元组的列表。没有参数时,它返回一个空的列表。
a = ['张三','小花','老王']
b = ['男','女','男']
c = ['已婚','已婚','未婚']
z = zip(a,b,c)
print(type(z)) # 注意:python3 不再返回列表,而是返回zip对象
print([x for x in z])
输出:
<class 'zip'>
[('张三', '男', '已婚'), ('小花', '女', '已婚'), ('老王', '男', '未婚')]
enumerate函数
enumerate(iterable, start=0)
返回一个enumerate对象此对象生成的类型为(索引,值)的元组,默认索引从零开始,也可以用第二个参数start指定
- iterable -- 一个序列、迭代器或其他支持迭代对象。
- start -- 下标起始位置
例:
day = ['None','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday']
for i in enumerate(day):
print('星期{} :{}'.format(*i))
输出:
星期0 :None
星期1 :Monday
星期2 :Tuesday
星期3 :Wednesday
星期4 :Thursday
星期5 :Friday
星期6 :Saturday
星期7 :Sunday
6.闭包
如果内层函数使用了外层函数中定义的局部变量,并且外层函数的返回值是内层函数的引用,就构成了闭包
其中定义在外层函数中但由内层函数使用的变量被称为自由变量。
一般情况下,如果一个函数结束,那么该函数中定义的局部变量就都会被释放。
然而闭包是一种特殊情况, 外层函数在结束时会发现其定义的局部变量将来会在内层函数中使用,此时
外层函数就会把这些自由变量绑定到内层函数。
因此所谓闭包, 实际上就是将内层函数的代码以及自由变量(外层函数定义,但会由内层函数使用)打包在一起。
def outer(x):
y = 10 # 定义局部变量y并赋值为10
def inner(z): # 在out函数中定义嵌套函数inner
nonlocal x,y
return x + y + z
return inner # 返回嵌套函数inner的引用 f = outer(5) # 将返回的inner函数赋给f
g = outer(50) # 将返回的inner函数赋给g
print('f(20)的值为:',f(20))
print('g(20)的值为:',g(20))
print('f(30)的值为:',f(30))
print('g(20)的值为:',g(30)) 输出结果:
f(20)的值为: 35
g(20)的值为: 80
f(30)的值为: 45
g(20)的值为: 90
提示:
闭包的主要作用在于可以封存函数执行的上下文环境。
比如,上例通过两次调用outer函数形成了两个闭包 f 和 g 。这两个闭包具有相互独立的上下文
环境(一个闭包(f)中x = 5,y = 10,另一个闭包中x = 50,y = 10),且每个闭包可多次调用。
7.装饰器(Decorator)
利用装饰器,可以在不修改已有函数的情况下向已有函数中注入代码,使其具备新的功能。
比如利用装饰器可以将日志处理,执行事件计算,性能测试,事务处理等较为通用且与函数功能本身无关的代码注入到不同的函数中,从而使得代码更加简洁。
一个装饰器可以为多个函数注入代码, 一个函数也可以注入多个装饰器的代码
本质上,装饰器就是一个返回函数的高阶函数。
实例1:
def deco(func): # 定义装饰器函数deco
def inner(*args, **kwargs):
print('deco begin')
func(*args, **kwargs)
print('deco end')
return inner # 返回函数inner的引用 @deco #语法糖,相当于在f函数执行前执行了f = deco(f)
def f(a,b,c):
print('a+b+c =',a+b+c) f(1,2,3)
输出结果:
deco begin
a+b+c = 6
deco end
7.2 带参数和有返回值的装饰器
装饰器还有更大的灵活性,例如带参数的装饰器,在上面的装饰器调用中,装饰器函数的参数就是业务函数 f。
装饰器的语法允许我们在调用时,提供其他参数,比如@deco(a) 。
这样就Wie装饰器的编写和使用提供了更大的灵活性。比如,我们可以在装饰器中指定日志的等级,因为不同业务
函数可能需要的日志等级是不一样的。
另外有些业务函数有自己的return值,所以我们在装饰器函数中也要设定返回值,即将业务函数的返回值在装饰函数中再返还给业务函数。示例如下:
import logging def use_deco(level): # 这个函数将装饰器参数传到内部环境中
def deco(func): # 真正的装饰器函数
def wrapper(*args, **kwargs): #内部用来实现装饰功能的函数
if level == 'warn':
logging.warning("%s is running" % func.__name__) # 打印一个警告信息; 每个函数对象都有一个__name__属性,可以拿到函数的名字
elif level == "info":
logging.info("%s is running" % func.__name__) # 默认日志级别是warning,所以info不会被打印
return func(*args) # 返回业务函数的返回
return wrapper # 返回函数wrapper的引用
return deco # 返回装饰器函数的引用 @use_deco(level='warn') #语法糖,还是相当于@deco(f = deco(f)),因为use_deco(level='warn') 返回的是deco
def f(a,b,c):
print('a+b+c =',a+b+c)
return a * b * c a = f(1,2,3)
print('a*b*c =',a) 运行结果:
a+b+c = 6
WARNING:root:f is running
a*b*c = 6
装饰器顺序
一个函数还可以同时定义多个装饰器,比如:
@a @b @c def f(): pass
他的执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器,它等效于
f = a ( b ( c ( f ) ) )
Python基础复习函数篇的更多相关文章
- Python基础复习面向对象篇
目录 类与对象的概念 实例方法 实例变量 初始化方法 析构方法 常用内置方法 继承 类方法与静态方法 动态扩展类与实例 @property装饰器 概述 面向对象是当前流行的程序设计方法,其以人类习惯的 ...
- python基础——匿名函数
python基础——匿名函数 当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便. 在Python中,对匿名函数提供了有限支持.还是以map()函数为例,计算f(x)=x2时 ...
- python基础——返回函数
python基础——返回函数 函数作为返回值 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回. 我们来实现一个可变参数的求和.通常情况下,求和的函数是这样定义的: def calc_ ...
- python基础——sorted()函数
python基础——sorted()函数 排序算法 排序也是在程序中经常用到的算法.无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小.如果是数字,我们可以直接比较,但如果是字符串或者两个d ...
- python基础——filter函数
python基础——filter函数 Python内建的filter()函数用于过滤序列. 和map()类似,filter()也接收一个函数和一个序列.和map()不同的是,filter()把传入的函 ...
- python基础——匿名函数及递归函数
python基础--匿名函数及递归函数 1 匿名函数语法 匿名函数lambda x: x * x实际上就是: def f(x): return x * x 关键字lambda表示匿名函数,冒号前面的x ...
- 八. Python基础(8)--函数
八. Python基础(8)--函数 1 ● 函数返回布尔值 注意, 自定义的函数也可以是用来作逻辑判断的, 例如内置的startswith()等函数. def check_len(x): ' ...
- python基础之函数详解
Python基础之函数详解 目录 Python基础之函数详解 一.函数的定义 二.函数的调用 三.函数返回值 四.函数的参数 4.1 位置参数 4.2 关键字参数 实参:位置实参和关键字参数的混合使用 ...
- 第七篇 python基础之函数,递归,内置函数
一 数学定义的函数与python中的函数 初中数学函数定义:一般的,在一个变化过程中,如果有两个变量x和y,并且对于x的每一个确定的值,y都有唯一确定的值与其对应,那么我们就把x称为自变量,把y称为因 ...
随机推荐
- gensim的word2vec如何得出词向量(python)
首先需要具备gensim包,然后需要一个语料库用来训练,这里用到的是skip-gram或CBOW方法,具体细节可以去查查相关资料,这两种方法大致上就是把意思相近的词映射到词空间中相近的位置. 语料库t ...
- Fish Shell使用心得
Fish的官网宣传语是 Finally, a command line shell for the 90s. 翻译过来就是 Fish shell 是一个为90后准备的 shell. 有人说:" ...
- 解决某些手机RadioGroup中的RadioButton不居中(右移)问题
最近一直在忙一个项目,页面的基本框架类似于QQ那样,有底部导航栏的,遂采用的是RadioButton来实现的.本来一直在我的模拟器上测试,页面展示是没啥问题的,效果图如下: 可是,坑爹的事今天却发生了 ...
- EL表达式中的empty和null
EL表达式中的empty和null 先说一下EL表达式中的null和empty区别,然后再说说最近在项目中出现的一个有趣的问题. EL中的null和empty都可用来判断值是否为空,但两者存在略微的区 ...
- JAVA之NIO按行读写大文件,完美解决中文乱码问题
;//一次读取的字节长度 File fin = new File("D:\\test\\20160622_627975.txt");//读取的文件 File fout = new ...
- 【DCN】Wireless Intranet Captive Portal
Wireless Intranet Captive Portal 配置AAA服务Radius认证 radius-server key 0 radius radius-server authentica ...
- java什么叫面向对象?
面向对象(Object-Oriented,简称OO)就是一种常见的程序结构设计方法. 面向对象思想的基础是将相关的数据和方法放在一起,组合成一种新的复合数据类型,然后使用新创建的复合数据类型作为项目的 ...
- [转]C#中 ??、 ?、 ?: 、?.、?[ ] 问号
1. 可空类型修饰符(?) 引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; 是正确的,int i=null; 编译器就会报错.为了使值类型也 ...
- springmvc单Redis实例实现分布式锁(解决锁超时问题)
一.前言 关于redis分布式锁, 查了很多资料, 发现很多只是实现了最基础的功能, 但是, 并没有解决当锁已超时而业务逻辑还未执行完的问题, 这样会导致: A线程超时时间设为10s(为了解决死锁问题 ...
- SpringBoot集成thymeleaf(自定义)模板中文乱码的解决办法
楼主今天在学习SpringBoot集成thymelaf的时候报了中文乱码的错误,经过网上的搜索,现在得到解决的办法,分享给大家: package com.imooc.config; import or ...