目录
函数的基础
形参:
实参:
动态传参:
不容易理解的地方:
return 返回值
命名空间
函数名:
闭包
如何分辨闭包:
闭包的作用:
迭代器:
递归:
装饰器:
作用:
使用情景:
扩展(带参装饰器)
生成器的三种创建办法:
定义:
优点:
使用方式:
推导式
列表推导式 [结果 for 变量 in 可迭代对象 if 筛选]
字典推导式 {键 : 值 for 变量 in 可迭代对象 if 筛选} 结果是
集合推导式 {结果 for 变量 in 可迭代对象 if 筛选}
函数的基础
# 申明方法
def 方法名(形参):
代码块
# 调用方法
方法名(实参)
def demo(name,age):
print(f'(我是{name},我今年{age}岁))
#调用方法
demo('admin',12)
形参:
位置形参:def demo(name,age)
默认值形参:def demo(name,age=12)
二者可以混合使用,但是 位置形参 必须在默认值形参之前
实参:
位置实参:demo('admin',12)
关键字实参: demo('admin',age=12)
二者可以混合使用,但是 位置实参 必须在关键字实参之前
动态传参:
*参数 是位置参数
**参数 是关键字参数 方法接受到的是字典
位置参数>动态位置参数>关键字参数>动态关键字参数
在形参上:*聚合 **聚合
在实参上:*打散 **打散
格式:
*args 接受所有位置参数
lis = [1,2,3,4]
def function(*args): # 聚合 将打散的 内容 再次组成元组形式 (1,2,3,4)
print(args)
print(*args)
function(lis) #
function(*lis) #打散 *lis实际上就是 1,2,3,4
#结果:
([1, 2, 3, 4],)
[1, 2, 3, 4]
(1, 2, 3, 4)
1 2 3 4
**wargs 接受所有关键字参数*******************************************
dir = {'a':1,'b':2,"c":3,"d":4}
def function(**kargs): #这里将其聚合成 {'a':1,'b':2,"c":3,"d":4}
# print(**kargs) #报错 TypeError: 'a' is an invalid keyword argument for this function
# print(*kargs) # a b c d
print(kargs) #{'a': 1, 'b': 2, 'c': 3, 'd': 4}
function(**dir) # 其实这里的是 a=1 b=2 c=3 d=4
# function(*dir) #报错 TypeError: function() takes 0 positional arguments but 4 were given
# function(dir) #报错 TypeError: function() takes 0 positional arguments but 1 was given
#注意 :
dir = {'a':1,'b':2,"c":3,"d":4}
def function(**kwargs):
print(**kwargs) #报错 TypeError: 'a' is an invalid keyword argument for this function
function(**dir)
为什么打印 **kwargs 会报错的原因是:
字典前加 ** 会将字典打散为 a=1,b=2,c=3,d=4。
传入 function(**kwargs)方法后会被 **kwargs 全部接受 聚合成 {'a': 1, 'b': 2, 'c': 3, 'd': 4}
而 print(**字典) 则会将 字典再次打散为关键字参数,
但是print 的方法的参数中是没有 **kwargs(接受所有的关键字参数的) , 因此会报错
但是 print()方法中是有 *args 参数的,也就是为什么print(*args) 并不会报错
不容易理解的地方:
def func(**kwargs):
print(kwargs)
dic = {"1":1}
func(**dic)
#结果: {'1': 1}
#减少写参数量
# dic = {"1":1}
# func(**dic) 等同于 func("1"=1) 虽然后者报错,但是在实际空间中是以这种方式存储
return 返回值
def demo(name,age):
print(f'(我是{name},我今年{age}岁))
return
print("这句话不会执行")
#调用方法
demo('admin',12)
注意:在一个方法体内,return之后的代码都不会执行到
命名空间
内置命名空间(优先级最高)
存放Python解释器为我们提供的名字,其中就包括内置函数,list,dict,tuple,set,str,int等都属于内置空间的。
全局命名空间
局部命名空间:函数内部
取值顺序:就进原则
globals()函数来查看全局作用域中的内容
locals()来查看当前作用域的内容
global 变量名 : 表示使用全局变量
在局部变量中使用,当全局变量中没有该参数时,则会将局部变量升级为 全局变量 (不推荐)
nonlocal 变量名 : 找局部作用域中,离他最近的那层的变量给引用过来,。如果除全局外的局部都不存在改变量则会报错(No find)
函数名:
def func():
pass
函数名可以当作值去赋值给变量
a = func
a() #调用的是func()
函数名可以当作参数传递给函数
def func2(msg):
print(msg)
func2(func) #执行后的结果 打印的是 func方法的内存地址
函数名可以当作函数返回值,注意:返回值不能加括号
def func():
def func_copy():
pass
return func_copy
print(func()) #打印的是 func_copy的内存地址
print(func()()) #打印的是 func_copy的方法内容
函数名可以当作元素存放一个容器里
def func():pass
def func2():pass
def func3():pass
li = [func,func2,func3] #列表中存的其实是 每个方法的内存地址
for i in li:
i() #打印每一个方法
查看函数的内存地址 print(函数名)
print(func)
闭包
如何分辨闭包:
闭包必须是嵌套函数,内部函数在使用外部变量(非全局变量)就是闭包。
可以使用方法名.__closure__ 查看该函数是否为闭包 只要返回值不是None,他就是闭包
def func():
n = 1
def func2():
print(n)
return func2 #注意这里的返回值 只是func2的方法名,也就是将其的地址返回。
func()()
闭包的作用:
1.可以读取到其他函数内部的变量
2.可以将变量保存在内存中,使其生命周期增强
3.可以保护其内部变量不受外界影响,不被修改,做到私有化
迭代器:
lst = [1,2,3,4,5]
l = lst.__iter__() # 从一个可迭代对象转换成迭代器
print(l.__next__()) #从迭代器中读取第一个
可迭代对象:具有 __iter__()方法
print(isinstance('列表等',Iterable)) 判断是否为可迭代对象
迭代器:拥有 __iter__()方法和__next__() 方法
print(isinstance('列表等',Iterator)) 判断是否为迭代器
# for循环机制
li = [1,2,3,4,5,6]
for i in li:
print(i)
# 等价于
li2 = li.__iter__()
while True: # 循环:
try:
print(li2.__next__()) # 获得下一个值:
except StopIteration:
break # 遇到StopIteration就退出循环
递归:
其实就是方法自己本身再调用自己
# 一个简单的递归
def fun(n):
print(n)
n += 1
fun(n)
fun(1)
#结果会报
# RecursionError: maximum recursion depth exceeded while calling a Python object
递归注意事项:有进也有出
递归的最大深度:官方定义是 1000,而实际上测试 只是 998
# 递归求阶乘
def factorial(n):
if n == 1 :
return 1
else:
return n*factorial(n-1)
递归的深度可以修改:
import sys
sys.setrecursionlimit(int num) #调用sys系统模块
装饰器:
装饰器的本质其实就是 闭包
举一个简单的装饰器
import time
def fun(a, b):
print('我是fun',a,b)
def test(fun):
def time_fun(*args,**kwargs):
star = time.time() #时间戳
time.sleep(2) #睡眠两秒钟
fun(*args,**kwargs)
end = time.time() #时间戳
print(end-star)
return time_fun #闭包功能
fun = test(fun) #将 time_fun函数的内存地址赋值给fun
fun(1,2) #虽然看见的是fun函数,但是实际走的却是time_fun函数
# 结果:
# 我是fun 1 2
# 2.000408411026001
可以使用@符 升级为:
@ 后跟 装饰器的名称 整体等同于 被装饰函数名称 = 装饰器名称(被装饰函数名称)
import time
def test(fun):
def time_fun(*args,**kwargs):
star = time.time() #时间戳
time.sleep(2) #睡眠两秒钟
fun(*args,**kwargs)
end = time.time() #时间戳
print(end-star)
return time_fun #闭包功能
@test #fun = test(fun)
def fun(a, b):
print('我是fun',a,b)
fun(1,2) #虽然看见的是fun函数,但是实际走的却是time_fun函数
#结果相同
作用:
在开发阶段要满足 开放封闭 原则 (开放是指:扩展功能开放。 封闭是指:源码封闭,不允许其他人修改)
装饰器可以实现不改变调用函数名的情况下,实现对本来函数的功能实现扩展
使用情景:
测试函数的运行时间
登陆校验
扩展(带参装饰器)
import time
def all(name):
def test(fun):
def time_fun(*args, **kwargs):
star = time.time() #时间戳
time.sleep(2) #睡眠两秒钟
print(name)
fun(*args, **kwargs)
end = time.time() #时间戳
print(end-star)
return time_fun #闭包功能
return test
@all('a') #fun = all('a')(fun) fun(1,2)
def fun(a, b):
print('我是fun', a, b)
fun(1,2) #虽然看见的是fun函数,但是实际走的却是time_fun函数
1.生成器的三种创建办法:
1.通过生成器函数 关键字 yield
def func():
print(1)
yield 1
print(2)
yield 2
l = func()
print(l.__next__())
print(l.__next__())
# print(l.__next__()) #报错,StopIteration
2.通过生成器表达式创建生成器
生成器表达式:
(结果 for 变量 in 可迭代对象 if 筛选) #重点是小括号
get1 = ( i for i in range(10) if i%2 == 0)
print(get1)
#结果:at 0x0000017DB9320938>
3.通过数据转换
2.生成器函数定义:
函数中包含了yield的就是生成器函数
注意:生成器函数被执行,获取到的是生成器,而不是函数的执行
yield from
def func():
li = [1,2,3,4]
yield from li
f = func()
for i in f:
print(i, end=",")
#结果:1,2,3,4
3.生成器的优点:
li = []
def func():
for i in range(1000):
li.append(i)
print(li)
#比较浪费空间,一次性取完
def func():
for i in range(1000):
yield i
f = func()
for i in range(10):
print(f.__next__())
#需要多少取多少
4.使用方式:
1. __next__()
get1 = ( i for i in range(10) if i%2 == 0) #生成器就是一个自己写的迭代器
#方式一:
for i in get1:
print(i,end=" ")
#方式二:
for i in range(5):
print(get1.__next__(),end=" ")
#结果:0 2 4 6 8
2.send(值) 给上一个yield位置传一个值 #send其实有next方法和传值方法
def func():
for i in range(10):
print(i)
l = yield "你好"
print(l)
f = func()
print(f.__next__()) #第一次执行,会执行完yield,暂留在那里
print(f.send("我不好")) #使用send会将参数赋值给上一次暂留位置,也就是程序中的l ,然后继续执行,知道下一个yield暂停
#结果:
# 0
# 你好
# 我不好
# 1
# 你好
注意点:send在使用时,如果没有先使用 __next__方法,则send()方法中的参数必为None
yield和return的区别:
yield和return的效果是一样的,但是还是有点区别
yield是分段来执行一个函数 yield 后面跟的相当于一个输出语句
return是直接停止这个函数
send和__next__()一样都可以让生成器执行到下一个yield
send和__next__()区别:
send 和 next()都是让生成器向下走一次
send可以给上一个yield的位置传递值,不能给最后一个yield发送值,在第一次执行生成器的时候不能使用send()
第一次调用的时候使用send()也可以但是send的参数必须是None
5.推导式
1.列表推导式 [结果 for 变量 in 可迭代对象 if 筛选]
li = [i for i in range(10) if i%2 == 0]
print(li)
#结果:[0, 2, 4, 6, 8]
2.字典推导式 {键 : 值 for 变量 in 可迭代对象 if 筛选} 结果是
li_1 = [1,2,3,4]
li_2 = [1,2,3,4]
dic = {li_1[i]:li_2[i]for i in range(len(li_1))}
print(dic)
#结果:{1: 1, 2: 2, 3: 3, 4: 4}
3.集合推导式 {结果 for 变量 in 可迭代对象 if 筛选}
set1 = { i for i in range(10) if i%2 == 0}
print(set1)
#结果:{0, 2, 4, 6, 8}