当前位置:硬件测评 > python基础知识

python基础知识

  • 发布:2023-09-29 20:13

Python其他知识目录

1。学习装饰器之前的热身准备

1.1 装饰器介绍


1.2装饰器预热分析

1)
def 函数():
经过
v1 = 10
v2 = func #给变量赋值函数名和给变量赋值是一样的。函数名赋予函数所在的内存地址。
打印(v1,v2)
------------ 结果:
10 <函数 func 位于 0x01E78D20>
2)
def 基础():
打印(1)
def 栏():
打印(2)
条= 底座
酒吧()
---------------- 结果:
1
#代码分析:bar重新赋值后,不再指向之前的函数,而是指向base指向的函数。 
执行栏表示执行基本功能
3) def 函数(): 定义内部(): 经过 返回内 v = func() print(v) # 内部函数 -------- 结果: .内部位于0x00638D20> #代码分析:func的返回值是内部函数的名称。如果打印v,则显示v指向内部函数的地址。 4) def 函数(参数): 定义内部(): 参数() 返回内 def f1(): 打印(123) v1 = func(f1) v1() ---------- 结果: 123#代码分析:使用f1函数名作为func的参数,执行func返回内部函数的地址。即v1是参数为
f1函数名的内部函数地址。执行v1函数表示执行内部函数,参数为f1。在内部函数内部,执行 f1()
函数。然后找到f1函数,看到它打印出123。f1的返回值为None。内部的返回值为None。
5) def 函数(参数): 定义内部(): 参数() 返回内 def f1(): 打印(123) 返回666 v1 = func(f1) result = v1() # 执行内部函数 / f1 包含函数 -> 123 打印(结果)#无 -------------------------------- 结果: 123 没有任何 #代码分析:(1)以f1函数名作为参数,执行func函数。 (2)func函数被执行,返回值,即内部子函数inner
的地址,被赋值给v1。由于执行func时就实现了闭包,所以执行v1时的参数是f1(3)。执行v1(),即执行内部函数。
执行完内部函数后,将内部返回值None赋给result。内部函数执行过程中,执行了v1的参数f1函数
,打印123,返回666。 (4)result接收的是inner的返回值None,不是f1执行的返回值。因此 ​​ 打印 None 而不是 666。 6) def 函数(参数): 定义内部(): 返回arg() 返回内 def f1(): 打印(123) 返回666 v1 = func(f1) result = v1() # 执行内部函数 / f1 包含函数 -> 123 打印(结果)# 666 --------------- 结果: 123 666#代码分析:分析过程如图5所示,区别在于result接收到的值。这里result仍然接收v1()返回的值。
v1指向inner函数,v1()的返回值就是inner的返回值。 inner的返回值是arg()参数函数的返回值。
实现关闭。 inner的参数是f1,所以接收到的结果就成为f1的返回值。 f1的返回值为666,
所以result接收到的值为666。所以打印666。打印123的原理同5)
7) def 函数(): 打印(1) v1 = 函数 函数 = 666 v1() 打印(函数) ------------ 结果: 1 666 #代码分析:func被赋值给v1,v1和func共同指向func
表示的函数的内存地址(相当于v1复制了func函数的地址信息,直接具备了查找函数的能力) 。
func被重新赋值,func变量指向666的内存地址。虽然func被重新赋值,但是并不影响v1。当v1执行时,
仍然执行该函数,但func代表新的内容

2。装饰器学习

1)
def 函数(参数):
定义内部():
打印('之前')
v = arg()
打印(''返回v
返回内
定义索引():
打印('123')
返回'666'
(1)示例1:
v1 =index() # 执行index函数,打印123并返回666赋值给v1。
-------- 结果:
123
#代码分析:执行index()函数,打印123,并将返回值index()‘666’赋给v1
(2)示例2:
v2 = func(index) # v2 为内函数,arg=index 函数索引 = 666
v3 = v2()
------------ 结果:
前
123
后
#代码分析:
执行函数func,参数为index。
func的返回值是子函数内部,并赋值给v2。重新赋值index为666。执行v2()时,因为实现了闭包,
,所以执行v2时,相当于执行参数index的内层子函数。执行inner时,先打印before。当
执行arg()时,它会执行索引函数。打印 123 并将 666 返回给变量 v。然后返回到内部函数并继续执行。
之后打印。返回666。inner的返回值666是v2(),所以v3
=“666”。 v = arg() return v 实现原函数的执行,并返回原函数的返回值。然而,在该函数执行之前和该函数执行之后
还执行其他操作。就是在功能上添加功能。这是一个装饰器。 (
3) v4 = func(索引) 索引 = v4 # 索引 ==> 内部 指数() ---------- 结果: 前 123 后 #代码分析。与2相同。将index函数传递到func函数中。 func执行后,将内部函数地址返回给v4。然后Index接收到
内部函数的地址,然后执行内部函数。由于实现了闭包,这里的args指向原来的索引函数地址,所以执行完
后会打印123。其他打印操作在该功能执行之前进行。 (
4)装饰器的一种表达方式 索引 = func(索引) 指数() -------------- 结果: 前 123 后 #代码分析:其实就是将原函数索引的地址作为参数传入到unc函数中。然后在func函数的子函数中,在执行
索引原函数之前和之后添加新函数,并利用闭包原理返回子函数名称。并将子函数名称重新分配给
索引函数。让新的索引函数在原来的基础上有了新的功能。(
5)装饰器的正确表示: def 函数(参数): 定义内部(): 打印("") v = arg() 返回v 返回内 # 第一步:执行func函数,传递以下函数参数,相当于:func(index) # 步骤2:将func的返回值重新赋值给下面的函数名。索引 = func(索引) @func 定义索引(): 打印(123) 返回666 打印(索引) 指数() ---------- 结果: .内部位于0x00587D20>123 #代码分析:从上面可以看出,index函数指向的地址就是inner函数。也就是说。将函数地址传递给func函数进行处理和装饰后,
将其重新分配给index函数。当再次执行该函数时,会找到新函数的地址并执行。 执行过程为:执行index()函数。当你在index上看到@func时,这意味着使用了装饰器,因此该函数会找到func,
并将index作为参数传入。然后将func的返回值重新赋值给index,即index
= func(index)。
执行index()时,相当于inner()执行inner函数。内部函数内参数的执行仍然指向原始索引。
新索引指向内部函数。内部函数的返回值被定义为原始索引的返回值。执行原索引函数,并在原函数
前后执行新添加的代码,实现与原函数相同功能的同时添加新函数。这些过程是内部函数
执行的操作,也就是新索引执行的操作。因此,通过添加装饰器,可以在保持原有功能不变的情况下添加新功能。

3。如何编写和使用装饰器

1)#装饰器的编写

def x(func):
def y(): #定义一个装饰器,传入参数作为要装饰的函数,返回值作为子函数名。将子函数名称分配给要装饰的函数,并为要装饰的函数分配新值。 。
# 前
ret = func() # 装饰器定义一个子函数。传入的参数在子函数中执行,也就是要装饰的函数。并接收要装饰的函数的返回值作为子函数的返回值。因为
# #后面要装饰的函数名指向了装​​饰器子函数的内存地址,也就是说执行新装饰的函数就是执行这个子函数。因此子函数的返回值必须与原函数的返回值一致才可以被
return ret # 修饰。子函数内部原函数执行完毕后的返回值作为子函数的返回值,这样两者就一致了。这样就保证了
return y #修饰前后原函数的返回值不变,保证了原函数的功能不变。以这个为基础。然后在原函数执行前后添加新函数,这样
#装饰器的应用#达到了在原函数中添加新函数同时保证原函数不改变的目的(想想,之前原来的函数被执行了,后续的操作是否也是函数执行的过程?有时间我会验证一下)

@x
def索引():
  返回10
@x
def管理():   pass
#执行功能,自动触发装饰器
v = index()
print(v)
#装饰器原理分析:
#定义一个装饰器,传入参数作为要装饰的函数,返回值是子- 函数名称。将子函数名称分配给要装饰的函数,并为要装饰的函数分配新值。 。 #装饰器定义了一个子函数。传入的参数在子函数中执行,也就是要装饰的函数。并接收要装饰的函数的返回值作为子函数的返回值。因为
#要装饰的函数名指向装饰器子函数的内存地址,也就是说执行新装饰的函数就是执行这个子函数。因此,子函数的返回值必须与未使用
#修饰之前的原函数的返回值保持一致。将子函数内部原函数执行后的返回值作为子函数的返回值,使两者保持一致。 。这样就保证了
#原函数的返回值在修饰前后保持不变,保证了原函数的功能不变。以这个为基础。然后在原函数执行前后添加新函数,这样
#就达到了在保证原函数不改变的情况下在原函数中添加新函数的目的(想想是否是在原函数执行前后的操作原函数的执行也可以是函数执行过程,有时间请验证一下)

[1]原功能:
def 函数():
print("小马过河")
乐趣()
-------- 结果:
小马过河
[2] 原函数添加装饰器后的代码执行
def 包装器(函数):
定义内部():
print("我是",end="")
返回 func()
返回内
@包装器
def 函数():
print("小马过河")
乐趣()
---------- 结果:
我是过河的小马

2)装饰器书写格式

def 外部函数(参数):
  def 内部函数(*args、**kwargs):
    返回参数(*args、**kwargs)   返回内部函数

#外层函数的返回值是内层函数的名称。内存函数的返回值就是要修饰的函数(func())的返回值。内部函数必须使用通用参数传递。内参数的返回值的参数也是通用参数。记得给外层函数添加一个参数接收变量
#内层函数和返回原函数参数必须统一。统一参数的目的是为了将参数传递给原来的索引函数

实验案例1:为已知为单参数的函数添加装饰器

[1] 实验案例 一个参数的函数,不添加装饰器
def 函数(参数):
打印(参数)
func("小马过河")
---------------- 结果:
小马过河
[2]添加装饰器但装饰器未接收参数时出错:
def 包装器(函数):
定义内部():
print("我是",end="")
返回 func()
返回内
@包装器
def 函数(参数):
打印(参数)
func("小马过河")
--------------- 结果:
func("小马过河")
类型错误:inner() 接受 0 位置参数,但给出了 1
[3]装饰器中inner只添加一个参数或者在装饰之前在原函数中添加一个参数都会报错。
def 包装器(函数):
def 内部(参数):
print("我是",end="")
返回 func()返回内
@包装器
def 函数(参数):
打印(参数)
func("小马过河")
------------------ 结果:
返回函数()
类型错误: func() 缺少 1 所需的位置参数:'args'

def 包装器(func):
def 内部(args):
print(“我是”+args,end =“”)
返回 func()
返回内部 @wrapper
def func():
print()
func("小马过河")
------------结果:
I am Pony Crossing the River
#代码分析:func("Pony Crossing the River")的内存地址就是内部函数。内部函数接收参数,函数正常运行。 inner
中的func是原函数的地址。原来的函数没有传递参数,这里也没有传递参数。没有冲突,所以没有问题。这样一来,这样传递的参数就
正常运行了。
[4] 为内部子函数和原始函数执行添加参数。
def 包装器(函数):
def 内部(参数):
print("我是",end="")
返回 func(args)
返回内
@包装器
def 函数(参数):
打印(参数)
func("小马过河")
-------------------------------- 结果:
我是一匹过河的小马
[5]装饰器中的两个传参位置和func的传参位置名称可以不同。但装饰器中传入的两个参数的位置变量名必须相同。
def 包装器(函数):
def 内部(mcw):print("我是",end="")
返回 func(mcw)
返回内
@包装器
def 函数(参数):
打印(参数)
func("小马过河")
---------------------------- 结果:
我是一匹过河的小马
#总结:从上面可以看出。为只有一个参数的函数添加装饰器,并为装饰器的子函数和子函数内执行的函数添加参数。我分析如下:func有参数,需要传入才能正常执行。 func在子函数内部执行func()时,也需要参数才能正确执行。修饰后的新func指向内部函数的地址。 new func的执行需要一个参数位置,所以内部也必须添加一个参数位置来接收参数。可以这样理解:inner中的参数是新func接收参数的位置,inner中func执行的参数是旧func接收参数的位置。新func和旧func中传递的参数是相同的。这时候就有一个问题,就是新的func和旧的func的函数地址是否相同?这是一个验证:
def 包装器(函数):
def 内部(mcw):
print("我是",end="")
打印(函数)
返回 func(mcw)
返回内
@包装器
def 函数(参数):
打印(参数)
func("小马过河")
打印(函数)
---------------- 结果:
我是<功能函数位于0x02137DB0>
小马过河
.内部位于0x02137D20>#代码分析总结:从上面可以看出,打印(func)时,装饰器中原来函数的地址是0x02137DB0,外面打印出来的新的func地址是0x02137D20。两者明显不同(那么那个应该是旧地址,有时间研究一下)

实验案例2:为多个未知参数的函数添加装饰器

[1]原函数的执行状态
def func(*args):
mcw="".join(args)
打印(MCW)
func("小马过河","的弟弟---------------- 结果:
小马过河的弟弟
[2]添加装饰器后,传递和接收的参数数量不够,报错。
def 包装器(函数):
def 内部(mcw):
print("我是",end="")
返回 func(mcw)
返回内
@包装器
def func(*args):
mcw="".join(args)
打印(MCW)
func("小马过河","的弟弟-------------------- 结果:
func("小马过河","的弟弟)
类型错误:inner() 采用 1 位置参数,但给出了 2
[3]传递的参数个数设置为通用参数,装饰器正常执行。
def 包装器(函数):
def 内部(*args):
print("我是",end="")
返回 func(*args)返回内
@包装器
def func(*args):
mcw="".join(args)
打印(MCW)
func("小马过河","的弟弟------------------------ 结果:
我是小马过河的弟弟
实验3:传递参数**args
实验4; *args 和 **args 混合参数传递
------------------------结果:

实验3:**args的参数传递
实验4; *args 和 **args 的混合参数传递

3)装饰者申请格式

@Outer function
def index():
  pass
index()
#装饰器的用途是在上面添加@outer function原始函数(即装饰器函数)。告诉这个函数使用哪个装饰器。那么当这个函数执行的时候,这个函数就会找到装饰器,根据这个函数执行时的装饰器,这个函数和新的函数会一起实现。

4)问题:为什么要加*args、**kwargs

如果

4。带参数的装饰器

4.1 带参数的装饰器案例分析

1】不带参数就是这个样子
def 包装器(函数):
定义内部():
返回 [func() for i 范围内(0,) )]
返回内
@包装器
def 函数():
打印("mcw")
乐趣()
---------------- 结果:
中波
中波
中波
中波
中波
【2】传递给装饰器的参数如下
def 计数(计数):打印("计数")
def 包装器(函数):
打印("包装纸")
定义内部():
返回 [func() for i 范围(0,计数)]
返回返回包装纸
@count(5)
def 函数():
打印("mcw")
-------------------------------- 结果:
数数
包装纸
#代码分析:@count(5)发生了什么。从上面可以看出。执行count函数并传入5作为参数。 
打印“count”并返回包装函数名称。这时候@count(5)就变成了@wrapper。 @wrapper 执行包装函数
将 func 函数名称作为参数传递给函数,打印“wrapper”并返回内部函数名称,然后重新分配 func 指向内部函数。 【
3】向装饰器传入参数后执行被装饰的函数。 def 计数(计数): def 包装器(函数): 定义内部(): 返回 [func() for i 范围(0,计数)] 返回返回包装纸 @count(5) def 函数(): 打印("mcw") 乐趣() --------------- 结果: 中波 中波 中波 中波 中波#代码分析:从上面可以看出,这个装饰器达到了执行原函数5次的效果。并且次数是传入参数,方便修改。
向装饰器传递参数的方式是在装饰器函数的外层定义一个外层函数并接收参数。这里传递的参数是需要传入
装饰器并且想要在装饰器中使用的参数。返回值是装饰器的函数名。使用添加参数的装饰器,
原来的@wrapper改为@count(
5)。在这个过程中,@count(5)的外层实现了将参数5传入装饰器,然后将
转换为@wrapper的操作。接下来就是装饰器的功能了,暂时不说。 #总之: [
1]如何将参数传递到装饰器中:在装饰器函数外面包装一个函数。该外部函数接收的参数是您要传递给装饰器的
参数。外部函数的返回值是装饰器的函数名。使用装饰器将@decorator函数名改为@outer函数名的执行并添加参数
(即@outer函数(参数)) [
2] 向装饰器传递参数的作用:装饰器用于批量装饰函数。如果不是每个函数都需要装饰得一样,
那么可以通过装饰器传入判断参数,对对应的函数进行不同的装饰。比如:多个函数,
可以在@处定义每个函数的执行,这样每个函数装饰相同但时间不同;再比如,
装饰器可用于缓存和 djong 页面缓存。通过不同页面的参数来确定每个页面的缓存时间。 [
3]装饰器根据不同的功能实现添加不同的功能。 。方法:添加参数。然后做出判断。 (两个函数用于区分装饰,
可以写两个装饰器,也可以写一个带参数的装饰器)
[4] 传入参数的装饰器可以批量装饰函数,实现差异化装饰。 

4.2。总结:

#第一步:执行ret = xxx(index)
# 第二步:将返回值赋给索引= ret
@xxx
定义索引():
经过
# 第一步:执行v1 = uuu(9)
# 步骤2:ret = v1(索引)
# 第三步:索引= ret
@uuu(9)
定义索引():
经过# ################## 普通装饰器####################
def 包装器(函数):
def 内部(*args,**kwargs):
print(在调用原函数'之前打印(')
data = func(*args,**kwargs) # 执行原函数并获取返回值
print('调用调用函数后')
返回数据
返回内
@包装器
定义索引():
经过
# ################## 带参数的装饰器####################
def x(计数器):
def 包装器(函数):
def 内部(*args,**kwargs):
data = func(*args,**kwargs) # 执行原函数并获取返回值
返回数据
返回返回包装纸
@x(9)
定义索引():
通过

5。装饰器的应用之一就是批量计算函数执行时间

装饰器:在函数执行前后自动执行一个函数,不改变原函数内部代码。

导入时间
def 包装器(函数):
定义内部():
开始时间 = time.time()
v = func()
end_time = time.time()
print(结束时间-开始时间)
返回v
返回内
@包装器
def func1():
时间.睡眠(2)
打印(123)
@包装器
def func2():时间.睡眠(1)
打印(456)
func1()
func2()
-------------结果:
123
2.0001144409179688
456
1.0000572204589844
#代码分析:写一个装饰器,将每一个使用装饰器的函数,在原函数前面加一个时间,在原函数后面再加时间。
二者之差就是函数的执行时间。由于这里函数执行太快,于是用sleep来加长原函数的执行时间。

6、装饰器总结:

目的:在不改变原函数的基础上,再函数执行前后自定义功能。
应用场景:想要为函数扩展功能时,可以选择用装饰器。

 

相关文章

热门推荐