函数、迭代器、生成器、装饰器
函数
函数基础
一、为什么要使用函数
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。把重复的代码提取出来,节省代码量
二、函数分类
内置函数,如len(),sun()
自定义函数
三、如何定义函数
def 函数名(参数1,参数2,参数3,...): '''注释''' 函数体 return 返回的值
四、函数使用的原则:先定义,后使用
五、调用函数
1、如何调用函数:函数名加括号
2、函数的返回值
函数的返回值通常都是一个,如果出现 return a,b 这种情况,其实是表示一个元组
六、函数的参数
#1、位置参数:按照从左到右的顺序定义的参数
位置形参:必选参数
位置实参:按照位置给形参传值,顺序必须一一对应
#2、关键字参数:按照key=value的形式定义的实参
无需按照位置为形参传值
注意的问题:
1. 关键字实参必须在位置实参右面
2. 对同一个形参不能重复传值
#3、默认参数:形参在定义时就已经为其赋值
可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参)
注意的问题:
1. 只在定义时赋值一次
2. 默认参数的定义应该在位置形参右面
3. 默认参数通常应该定义成不可变类型,举例
def add_end(L=[]): print(id(L)) L.append('END') return L print(add_end()) print(add_end())
结果:
2822355733768
['END']
2822355733768
['END', 'END']
解释:python函数在定义好时,形参、内部参数等变量就已经有了固定的内存空间(变量始终指向那一块内存,不会更改)。默认参数形参变量如果是可变的,下一次调用该函数时,默认参数就已经发生了变化。
#4、可变长参数: 可变长指的是实参值的个数不固定
而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参对应有两种解决方案来完整地存放它们,分别是*args,**kwargs
===========*args===========
def foo(x,y,*args):
print(x,y)
print(args)
foo(1,2,3,4,5)
def foo(x,y,*args):
print(x,y)
print(args)
foo(1,2,*[3,4,5])
def foo(x,y,z):
print(x,y,z)
foo(*[1,2,3])
当形参为*args,实参可以用 *()或者 *[] 的方式将若干个参数打包发送给形参
===========**kwargs===========
def foo(x,y,**kwargs):
print(x,y)
print(kwargs)
foo(1,y=2,a=1,b=2,c=3)
def foo(x,y,**kwargs):
print(x,y)
print(kwargs)
foo(1,y=2,**{'a':1,'b':2,'c':3})
def foo(x,y,z):
print(x,y,z)
foo(**{'z':1,'x':2,'y':3})
当形参为**kwargs时,实参可以通过**{}的方式将若干参数打包发送给形参
===========*args+**kwargs===========
def foo(x,y):
print(x,y)
def wrapper(*args,**kwargs):
print('====>')
foo(*args,**kwargs)
#5、命名关键字参数:*后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递,可以保证,传入的参数中一定包含某些关键字
和关键字参数**kw
不同,命名关键字参数需要一个特殊分隔符*
,*
后面的参数被视为命名关键字参数(如果参数中已经有了可变参数*args,则不需要 * 来特别标明)
def foo(x,y,*args,a=1,b,**kwargs): print(x,y) print(args) print(a) print(b) print(kwargs) foo(1,2,3,4,5,b=3,c=4,d=5)
结果: 1 2 (3, 4, 5) 1 3 {'c': 4, 'd': 5}
闭包
一、函数是对象
函数可以当做参数传递,也可以返回一个函数
利用该特性,可以写成一个类似C语言switch case语法的功能,取代多分支if
def foo(): print('foo') def bar(): print('bar') dic={ 'foo':foo, 'bar':bar, } while True: choice=input('>>: ').strip() if choice in dic: dic[choice]()
二、函数嵌套、名称空间、作用域的概念
1、函数嵌套调用
函数嵌套定义
2、名称空间
存放名字的地方,x=1,1存3、放于内存中,那名字x存放在哪里呢?名称空间是存放名字x与1绑定关系的地方,L = [1,2,3],L存放在名称空间里,真正的列表在其他地方。
3、作用域
#1、作用域即范围
-全局范围(内置名称空间与全局名称空间属于该范围):全局存活,全局有效
-局部范围(局部名称空间属于该范围):临时存活,局部有效
内部的函数可以访问外部的变量,但是外面的函数访问不了内部函数
#2、作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关
#3、查看作用域:globals(),locals()
LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
locals 是函数内的名字空间,包括局部变量和形参
enclosing 外部嵌套函数的名字空间(闭包中常见)
globals 全局变量,函数定义所在模块的名字空间
builtins 内置模块的名字空间
闭包函数
内部函数包含对外部函数而非全局作用域的引用
def counter(): n = 0 def incr(): nonlocal n x = n n += 1 return x return incr c = counter() print(c()) print(c()) print(c()) print(c.__closure__[0].cell_contents) # 查看闭包的元素
结果:
0
1
2
3
闭包函数的意义:
返回的函数对象,不仅仅是一个函数,在该函数外还包裹了一个外层作用域(一般含是变量),这使得,该函数无论在何处调用,都优先使用自己外层包裹的作用域,相对于更外层的比如全局作用域。
实现延迟计算的功能:
普通函数调用后立即函数执行,闭包则是给函数包裹上了一层外层作用域,传了参数的功能。
