函数:
内置函数(链接)
一.函数初始
默认参数的陷阱
默认参数若是可变的数据类型,他始终使用的是一个内存地址。
def func1(x,l1=[]):
l1.append(x)
return l1
ret = func1(1)
ret1 = func1(100)
return是函数结束的标志,函数内可以写多个return,但只执行一次
无return 返回None
只写return,后面不写其他内容,也会返回None
return 逗号分隔多个值 返回元组
返回多个值,用多个变量接收
a,b,c,d = ret_demo2()
形参即变量名,实参即变量值
函数即变量 函数的赋值 f = func
命名关键字参数:*后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递
可以保证,传入的参数中一定包含某些关键字
def foo(位置形参,*args,默认参数,**kwargs):
函数体
return 返回值
动态参数
溢出的位置参数值以元祖形式赋给args ,溢出的关键字参数以字典的形式赋给kwargs
*args,**kwargs
函数定义时:*聚合 *args:实参里面所有的位置参数。
**kwargs:实参里面所有的关键字参数。
函数的调用时:* 打散。
形参的顺序:位置参数,*args,默认参数,**kwargs。
二.函数进阶
存放名字与值的关系’的空间起了一个名字-------命名空间。
全局名称空间。
临时名称空间。
内置名称空间。
全局作用域: 全局名称空间,内置名称空间。
局部作用域: 局部名称空间。
取值顺序:就近原则,从小到大。
加载顺序:加载的是名称空间。
global nonlocal
globals() locals() 以字典形式返回模块全部全局变量和局部变量
全局作用域:包含内置名称空间、全局名称空间
局部作用域:局部名称空间,只能在局部范围内生效
- 函数名的本质。
函数名本质上就是函数的内存地址。
-
1.可以被引用
-
2.可以被当作容器类型的元素
-
3.可以当作函数的参数和返回值
第一类对象(first-class object)指
1.可在运行期创建
2.可用作函数参数或返回值
3.可存入变量的实体。
- 一句话,函数名能当普通变量用
嵌套函数:
匿名函数:使用一次就释放
- lambda x,y:x**y
- 匿名函数主要是和其它函数搭配使用
高阶函数:
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
只需满足以下任意一个条件,即是高阶函数
- 接受一个或多个函数作为输入
- return 返回另外一个函数
def add(x,y,f):
return f(x) + f(y)
递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
查看递归次数
n = 1
def func(x):
print(x)
x+=1
func(x)
func(n)
def calc(n):
v = int(n/2)
print(v)
if v > 0:
calc(v)
print(n)
calc(10)
递归特性:
- 必须有一个明确的结束条件
- 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
- 递归效率不高,递归层次过多会导致栈溢出()
应用:二分查找
闭包原理
闭包函数:内部函数包含对外部作用域而非全剧作用域变量的引用,该内部函数称为闭包函数,并返回.
闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
应用领域:延迟计算(原来我们是传参,现在我们是包起来)
闭包作用:
当程序执行时,遇到了函数执行,他会在内存中开辟一个空间,局部名称空间,
如果这个函数内部形成了闭包,
那么他就不会随着函数的结束而消失。
name = 'alex'
def wraaper():
def inner():
print(name)
print(inner.__closure__) # None不是闭包函数
inner()
return inner
wraaper()
name = 'hqs'
def wraaper(n):
n = 'alex'
def inner():
print(n)
print(inner.__closure__) # cell at 0x000002AD93BF76D8 --> 是闭包函数
inner()
return inner
wraaper(name)
可迭代对象:Iterable
: str list dict,tuple,set,range()
对象内部含有iter方法就是可迭代对象.
print('__iter__' in dir(对象)) #返回True.False
from collections import Iterable #判断是否是可迭代对象
from collections import Iterator #判断是否是迭代器
print(isinstance('对象',Iterable)) # True/False
print(isinstance('对象',Iterator)) # True/False
可迭代对象满足可迭代协议。
迭代器:Iterator
对象内部含有__iter__方法且含有__next__方法就是迭代器.
文件本身就是迭代器对象
迭代器的缺点:
- 取值麻烦,只能一个一个取,只能往后取,
- 并且是一次性的,无法用len获取长度
可迭代对象不能取值,迭代器是可以取值的。
可迭代对象 --->(转化成)迭代器
迭代器=可迭代对象.iter() #等于 迭代器=iter(可迭代对象) #转化
1,将可迭代对象转化成迭代器。
2,调用next方法取值。
3,利用异常处理停止报错。
模式for循环
迭代器 = 可迭代对象.__iter__()
while 1:
try:
print(迭代器.__next__())
except StopIteration:
break
装饰器:
开放封闭原则:
软件上线后,对修改源代码是封闭的,对功能的扩展功能是开放的。
方案:装饰器
原则:
* 1,不修改原代码
* 2,不修改调用方式
目的:
遵循1和2的基础上拓展新功能
装饰器:
装饰为被装饰对象添加新功能
含义:
装饰器即在不修改被装饰对象源代码与调用方式的前提下,为被装饰对象添加新功能
装饰器 ==》函数
被装饰的对象 ==》函数
time.time() 获取当前时间(s)
生成器:就是自己python用代码写的迭代器,生成器的本质就是迭代器。
generator是可迭代对象 , 可用for循环和next()
用以下两种方式构建一个生成器:
- 1,通过生成器函数。
- 2,生成器表达式。
生成器函数 vs 迭代器:
- 迭代器是需要可迭代对象进行转化。可迭代对象非常占内存。
- 生成器直接创建,不需要转化,从本质就节省内存。
- send 与next一样,也是对生成器取值(执行一个yield)的方法。
- send 可以给上一个yield 传值。
- 第一次取值永远都是next。
- 最后一个yield 永远也得不到send传的值。
- yield 将值返回给 生成器对象.next()
迭代器.next() 相当于 next(迭代器)
把函数做成迭代器
* 对比return,可以返回多次值,挂起函数的运行状态
创建生成器:如下
def func1(): #生成器函数
print(1)
count = (yield 6)
print(count)
count1 = (yield 7)
print(count1)
yield 8
g = func1() #调用生成器函数创建生成器对象
print(next(g))
print(g.send('alex'))
print(g.send('alex'))
def cloth2(n):
for i in range(1,n+1):
yield '衣服%s号' % i
g = cloth2(10000)
for i in range(50):
print(g.__next__()) #停在50的位置
for i in range(50): #从51开始
print(g.__next__())
列表推导式
- 循环模式 : [变量(加工后的变量) for 变量 in iterable]
- 筛选模式 : [变量(加工后的变量) for 变量 in iterable if 条件]
优点:一行解决,方便。
缺点:容易着迷,不易排错,不能超过三次循环。
列表推导式不能解决所有列表的问题,所以不要太刻意用。
生成器表达式:
将列表推导式的 [] 换成() 即可。
三元表达式:ret = 'true' if 1 == 1 else 'false'
网友评论