python其他知识目录

1、装饰器学习前热身准备

1.1装饰器简介

1.2装饰器热身分析


def func():
pass
v1 =
v2 = func #将函数名赋予一个变量,就和变量赋值是同理。而函数名赋予的是函数所在的内存地址
print(v1,v2)
------------结果:
<function func at 0x01E78D20> )
def base():
print()
def bar():
print()
bar = base
bar()
----------------结果: #代码解析:另bar重新赋值之后,它不再指向之前的函数,而是指向base所指向的函数,
执行bar,就是执行base函数

def func():
def inner():
pass
return inner
v = func()
print(v) # inner函数
--------结果:
<function func.<locals>.inner at 0x00638D20>
#代码解析:func返回值是inner函数名,打印v,则显示v指向inner所在的地址

def func(arg):
def inner():
arg()
return inner
def f1():
print()
v1 = func(f1)
v1()
----------结果: #代码分析:将f1函数名作为func的参数,执行func返回inner函数的地址。即v1是带有参数为
f1函数名的inner函数地址。执行v1函数,就是执行inner函数,并且参数为f1。inner函数内部f1()
函数执行,再去找到f1函数,看它执行打印出123,f1的返回值是None。inner的返回值是None。

def func(arg):
def inner():
arg()
return inner
def f1():
print()
return
v1 = func(f1)
result = v1() # 执行inner函数 / f1含函数 ->
print(result) # None
------------------结果: None
#代码分析:()以f1函数名为参数,执行func函数。()func函数执行,并将返回值即内部子函数inner
的地址赋值给v1。由于func执行时实现了闭包,v1执行时的参数即为f1()执行v1(),即执行inner函数,
执行inner函数后并将inner的返回值None赋值给result。执行inner函数期间,是将v1的参数f1函数执行
一下,打印123,并返回666.()result接收的是inner的返回值None,而不是f1执行的返回值。所以
打印None,而非666。

def func(arg):
def inner():
return arg()
return inner
def f1():
print()
return
v1 = func(f1)
result = v1() # 执行inner函数 / f1含函数 ->
print(result) #
--------------结果: #代码分析:分析过程如5。区别在于result接收的值。这里result依旧接收v1()返回的值。
v1指向inner函数,v1()的返回值是是inner的返回值。inner的返回值是arg()参数函数的返回值。
实现了闭包的,inner的参数是f1,所以result接收的就成了f1的返回值。f1的返回值是666,
所以result接收的值是666。所以打印666.而123打印的原理如5)

def func():
print()
v1 = func
func =
v1()
print(func)
------------结果: #代码解析:func赋值给v1,v1和func共同指向func代表的函数内存地址
(相当于v1复制了一份func函数的地址信息,直接拥有找到函数的能力)。
func重新赋值,func变量指向666的内存地址。虽然func重新赋值了,但是不影响v1,执行v1,
还是执行那个函数,而func却是代表新的内容

2、装饰器学习


def func(arg):
def inner():
print('before')
v = arg()
print('after')
return v
return inner
def index():
print('')
return ''
()示例1:
v1 = index() # 执行index函数,打印123并返回666赋值给v1.
--------结果: #代码分析:执行index()函数,打印123,返回值index()‘’赋值给v1
()示例2:
v2 = func(index) # v2是inner函数,arg=index函数
index =
v3 = v2()
------------结果:
before after
#代码分析:
执行函数func,参数为index。
func返回值为子函数inner,并赋值给v2。将index重新赋值666。执行v2(),因为实现了闭包,
所以v2执行时,就相当于执行带了参数为index的inner子函数。执行inner先打印before,
执行arg()就是执行了index函数.打印123,返回666给变量v。然后回到inner函数继续往下执行。
打印after。返回666。inner的返回值666就是v2(),所以v3=“”。
v = arg() return v 实现了执行原函数并返回原函数的返回值。但是却在函数执行之前和函数执行
之后都多做了别的操作。就是实现了给函数增添功能,这就是装饰器。
()
v4 = func(index)
index = v4 # index ==> inner
index()
----------结果:
before after
#代码分析。与2相同。将index函数传入func函数,func执行后返回inner函数地址给v4,index再接收
inner函数的地址,然后执行inner函数。由于实现了闭包,这里的args指向的是原来的index函数地址所以
执行后打印123.在函数执行前有做了其他的打印操作。
()装饰器的一种表示方式
index = func(index)
index()
-------------结果:
before after
#代码解析:实则是将原函数index的地址作为参数传入到unc函数。然后在func函数的子函数中将这
个index原函数执行前执行后增添新的功能,利用闭包原理返回子函数名。并将子函数名重新赋值给
index函数。让新的index函数在原有基础上拥有了新的功能。 ()装饰器的正确表示方式:
def func(arg):
def inner():
print("after")
v = arg()
return v
return inner
# 第一步:执行func函数并将下面的函数参数传递,相当于:func(index)
# 第二步:将func的返回值重新赋值给下面的函数名。 index = func(index)
@func
def index():
print()
return
print(index)
index()
-----------结果:
<function func.<locals>.inner at 0x00587D20>
after #代码分析:由上可知,index函数指向地址为inner函数。也就是说。将函数地址传到func函数加工装饰之后
重新赋值给index函数。当这个函数再次执行时,就是找到新的函数的地址并执行。
执行过程为:执行index()函数,当看到index上面有@func时,就说明使用了装饰器,于是函数找到了func,
并将index以参数形式传入。然后将func的返回值重新赋值给index,即index = func(index)。
当index()执行时,就相当于inner()执行inner函数。inner函数内参数的执行还是指向原index。
新index是指向inner函数的。inner函数的返回值定义为原index的返回值。执行index原函数并执行原函数
前后新加的代码,实现原函数功能不变的同时,增添了新的功能。而这些过程是inner函数执行的操作,
也就是新的index的执行的操作。所以,添加了装饰器就实现在原函数不变的基础上增添新的功能。

3、装饰器的编写和使用方法

1)# 装饰器的编写

def x(func):
def y(): #定义一个装饰器,传参为要装饰的函数,返回值为子函数名。子函数名是要赋值给要装饰的函数的,将要装饰的函数重新赋予新值。。
# 前
ret = func() #装饰器定义一个子函数。子函数里执行传进去的参数即要装饰的函数。并接收要装饰的函数的返回值,作为子函数的返回值。因为
# 后 #要装饰的函数名指向了装饰器子函数的内存地址,即执行被装饰后的新的函数就是执行这个子函数。所以子函数的返回值要和原函数即被
return ret #装饰之前那个函数的返回值保持一致,子函数内部原函数被执行后的返回值作为子函数的返回值,这样就保持二者一致了。这样保证了
return y #原函数在被装饰之前和装饰之后的返回值不变,保证原函数的功能不变。在此基础之上。再到原函数执行之前和之后添加新的功能,这样就
# 装饰器的应用 #实现了保证原函数不改变的情况下,给原函数增添了新的功能(思考,原函数执行之前之后的操作是不是也可以是个函数执行的过程呢,有时间验证一下)

@x
def index():
  return 10
@x
def manage():
  pass
# 执行函数,自动触发装饰器了
v = index()
print(v)
#装饰器原理分析:
#定义一个装饰器,传参为要装饰的函数,返回值为子函数名。子函数名是要赋值给要装饰的函数的,将要装饰的函数重新赋予新值。。 #装饰器定义一个子函数。子函数里执行传进去的参数即要装饰的函数。并接收要装饰的函数的返回值,作为子函数的返回值。因为
#要装饰的函数名指向了装饰器子函数的内存地址,即执行被装饰后的新的函数就是执行这个子函数。所以子函数的返回值要和原函数即被
#装饰之前那个函数的返回值保持一致,子函数内部原函数被执行后的返回值作为子函数的返回值,这样就保持二者一致了。这样保证了
#原函数在被装饰之前和装饰之后的返回值不变,保证原函数的功能不变。在此基础之上。再到原函数执行之前和之后添加新的功能,这样就
#实现了保证原函数不改变的情况下,给原函数增添了新的功能(思考,原函数执行之前之后的操作是不是也可以是个函数执行的过程呢,有时间验证一下)

[]原函数:
def func():
print("小马过河")
func()
--------结果:
小马过河
[]原函数加上装饰器后的代码执行
def wrapper(func):
def inner():
print("我是",end="")
return func()
return inner
@wrapper
def func():
print("小马过河")
func()
-----------结果:
我是小马过河

2)装饰器编写格式

def 外层函数(参数):
  def 内层函数(*args,**kwargs):
    return 参数(*args,**kwargs)
  return 内层函数

#外层函数返回值为内层函数名字。内存函数返回值为要装饰的函数的返回值(func())。内层函数要使用万能传参。内层参数返回值的参数也为万能传参。记得要添加一个外层函数的参数接收变量
#内层函数和return原函数参数要统一,参数统一的目的是为了给原来的index函数传参

实验案例一:给已知为单个传参的函数添加装饰器

[]实验案例   没有添加装饰器有一个参数的函数
def func(args):
print(args)
func("小马过河")
--------------结果:
小马过河
[]添加装饰器但是装饰器没有接收参数的报错情况:
def wrapper(func):
def inner():
print("我是",end="")
return func()
return inner
@wrapper
def func(args):
print(args)
func("小马过河")
---------------结果:
func("小马过河")
TypeError: inner() takes positional arguments but was given
[]只给装饰器中inner加上一个参数或者原函数被装饰前执行的加一个参数都报错
def wrapper(func):
def inner(args):
print("我是",end="")
return func()
return inner
@wrapper
def func(args):
print(args)
func("小马过河")
-----------------结果:
eturn func()
TypeError: func() missing required positional argument: 'args'
def wrapper(func):
def inner(args):
print("我是"+args,end="")
return func()
return inner
@wrapper
def func():
print()
func("小马过河")
------------结果:
我是小马过河
#代码分析:func("小马过河")的内存地址是inner函数,inner函数有接收参数,函数运行正常。inner
内的func是原函数的地址,原函数没有传参,这里也没有传参,没有冲突,所以没有问题。如此传参都是
正常运行。
[]给inner子函数和原函数执行都加上一个参数。
def wrapper(func):
def inner(args):
print("我是",end="")
return func(args)
return inner
@wrapper
def func(args):
print(args)
func("小马过河")
------------------结果:
我是小马过河
[]装饰器中的两个传参的位置和func的传参的位置接收变量的名字可以不一样。但是装饰器中的两个传参的位置变量名字要一样才可以。
def wrapper(func):
def inner(mcw):
print("我是",end="")
return func(mcw)
return inner
@wrapper
def func(args):
print(args)
func("小马过河")
----------------------------结果:
我是小马过河 #总结:由上可知。给有一个参数的函数添加装饰器,在装饰器的子函数以及子函数内执行的那个函数都要加上一个参数。本人如下分析:func是有参数的,需要传参进入才能正常执行。func在子函数inner中执行func()也是需要参数才可以正确执行。而装饰后的新的func是指向inner函数的地址的,新的func执行需要参数位置,所以inner也要添加一个参数位置接收传参。可以这样理解:即inner里的参数为新的func接收参数位置,inner里面func执行的参数为旧有的func接收参数的位置。新的func和旧有的func的传递的参数是一致的。此时有个疑问,就是新的func和旧有的func的函数地址是一样的吗,下面做个验证: def wrapper(func):
def inner(mcw):
print("我是",end="")
print(func)
return func(mcw)
return inner
@wrapper
def func(args):
print(args)
func("小马过河")
print(func)
----------------结果:
我是<function func at 0x02137DB0>
小马过河
<function wrapper.<locals>.inner at 0x02137D20>
#代码分析总结:由上可知,print(func)时,装饰器里面原函数的地址是0x02137DB0,而外面打印是新的func地址0x02137D20。二者明显不同(那么那个应该是旧有的地址呢,有时间研究一下)

实验案例二:给未知多个传参的函数添加装饰器

[]原函数的执行情况
def func(*args):
mcw="".join(args)
print(mcw)
func("小马过河","的弟弟")
--------------结果:
小马过河的弟弟
[]加上装饰器后传参接收的个数不够报错
def wrapper(func):
def inner(mcw):
print("我是",end="")
return func(mcw)
return inner
@wrapper
def func(*args):
mcw="".join(args)
print(mcw)
func("小马过河","的弟弟")
--------------------结果:
func("小马过河","的弟弟")
TypeError: inner() takes positional argument but were given
[]传参个数都设为万能传参,装饰器正常执行
def wrapper(func):
def inner(*args):
print("我是",end="")
return func(*args)
return inner
@wrapper
def func(*args):
mcw="".join(args)
print(mcw)
func("小马过河","的弟弟")
----------------------结果:
我是小马过河的弟弟 实验三:**args的传参
实验四;*args和**args混合传参 ----------------------结果:

实验三:**args的传参
实验四;*args和**args混合传参

3)装饰器应用格式

@外层函数
def index():
  pass
index()
#装饰器的使用就是在原函数上面添加@外层函数(即装饰器函数)。告诉这个函数是使用哪个装饰器。然后执行这个函数的时候这个函数就会找到装饰器,并在这个函数执行时按装饰器的来,本函数以及新增功能一并实现。

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

如果

4、带参数的装饰器

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

【】没带参数时是这样的
def wrapper(func):
def inner():
return [func() for i in range(,)]
return inner
@wrapper
def func():
print("mcw")
func()
----------------结果:
mcw
mcw
mcw
mcw
mcw
【】给装饰器中传入参数是这样的
def count(count):
print("count")
def wrapper(func):
print("wrapper")
def inner():
return [func() for i in range(,count)]
return inner
return wrapper
@count()
def func():
print("mcw")
------------------结果:
count
wrapper
#代码分析:在@count()的时候发生了什么呢。由上可知。执行了count函数,并将5作为参数传入参数。
打印“count”并返回wrapper函数名。这时@count()成了@wrapper。@wrapper执行wrapper函数
将func函数名作为参数传入函数,打印“wrapper”并返回inner函数名,然后重新赋值func指向inner函数。
【】给装饰器传入参数后执行被装饰的函数。
def count(count):
def wrapper(func):
def inner():
return [func() for i in range(,count)]
return inner
return wrapper
@count()
def func():
print("mcw")
func()
---------------结果:
mcw
mcw
mcw
mcw
mcw
#代码分析:由上可知,本装饰器实现了将原函数执行5次的效果。并且次数是传入的方便修改的参数。
给实现给装饰器传入参数的方法是在装饰器函数外层上定义一个外层函数,并接收传参。此处的传参是需要传入
装饰器,想要在装饰器中使用的参数。返回值是装饰器的函数名。使用加了参数的装饰器,由原来
的@wrapper改为了@count()。在此过程中,@count()外层实现了将参数5传入装饰器,然后转
为@wrapper的操作。再往后就是装饰器的功能了,暂且不说。 #综上:
[]给装饰器里传入参数的方法:在装饰器函数外再套一个函数。这个外层函数接收的参数为想要传入装饰器的
参数。外层函数的返回值是装饰器的函数名。使用装饰器由@装饰器函数名改为@外层函数名的执行并加上参数
(即@外层函数(参数))
[]给装饰器里传入参数的作用:装饰器是用来批量装饰函数的,如果不是每个函数都要做相同的装饰,
那么就可以在装饰器中通过传进来的参数进行判断,给对应函数进行不同的装饰。举个栗子:多个函数,
每个函数的执行此时可以在@那里定义一下,这样每个函数做了相同的装饰但是又有不同的次数了;又比如,
装饰器可以用在缓存,djong的页面缓存。在不同的页面利用传参判断每个页面缓存时间是多少。
[]一个装饰器根据不同函数实现增添不同的功能。。方法:添加传参。然后做判断。(两拨函数做差异化装饰,
可写两个装饰器,也可以写一个带传参的装饰器)
[4]带传参的装饰器,可以做对函数进行批量装饰,又能做到差异化装饰。

4.2、总结:

# 第一步:执行 ret = xxx(index)
# 第二步:将返回值赋值给 index = ret
@xxx
def index():
pass # 第一步:执行 v1 = uuu()
# 第二步:ret = v1(index)
# 第三步:index = ret
@uuu()
def index():
pass
# ################## 普通装饰器 #####################
def wrapper(func):
def inner(*args,**kwargs):
print('调用原函数之前')
data = func(*args,**kwargs) # 执行原函数并获取返回值
print('调用员函数之后')
return data
return inner @wrapper
def index():
pass # ################## 带参数装饰器 #####################
def x(counter):
def wrapper(func):
def inner(*args,**kwargs):
data = func(*args,**kwargs) # 执行原函数并获取返回值
return data
return inner
return wrapper @x()
def index():
pass

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

装饰器:在不改变原函数内部代码的基础上,在函数执行之前和之后自动执行某个功能。

import time
def wrapper(func):
def inner():
start_time = time.time()
v = func()
end_time = time.time()
print(end_time-start_time)
return v
return inner
@wrapper
def func1():
time.sleep()
print()
@wrapper
def func2():
time.sleep()
print()
func1()
func2()
-------------结果: 2.0001144409179688 1.0000572204589844
#代码分析:写一个装饰器,将每一个使用装饰器的函数,在原函数前面加一个时间,在原函数后面再加时间。
二者之差就是函数的执行时间。由于这里函数执行太快,于是用sleep来加长原函数的执行时间。

6、装饰器总结:

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

python基础知识-11-函数装饰器的更多相关文章

  1. python基础整理4——面向对象装饰器惰性器及高级模块

    面向对象编程 面向过程:根据业务逻辑从上到下写代码 面向对象:将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程 面向对象编程(Object Oriented Pro ...

  2. Python基础(八)装饰器

    今天我们来介绍一下可以提升python代码逼格的东西——装饰器.在学习装饰器之前我们先来复习一下函数的几个小点,方便更好的理解装饰器的含义. 一.知识点复习 1, 在函数中f1和f1()有什么不同,f ...

  3. python学习日记(函数--装饰器)

    楔子 前提,我有一段代码(一个函数). import time def run_time(): time.sleep(0.1) print('我曾踏足山巅') 需求1:现在,我想计算这段代码的运行时间 ...

  4. python语言中的函数装饰器

    装饰器 什么是装饰器? 装饰:给已有的对象(函数)添加新的功能 器:工具              在python中指具备某些功能的函数 装饰器:装饰器就是一个给其他函数增加功能的函数 一种设计原则: ...

  5. Python小白学习之函数装饰器

    装饰器 2018-10-25 13:49:37 装饰器从字面意思就是用来装饰的,在函数可以理解为:在函数中,我们不想影响原来的函数功能,又想给函数添加新的功能,这时候我们就用到了装饰器. 一般函数操作 ...

  6. Python学习第四十一天函数装饰器传参数的用法

    在不改变函数的结构的基础,我们给函数加新的功能,用是函数装饰器,如果要给函数传递参数,那么应该怎么做呢 @timerdef test2(name,age): time.sleep(3) print(' ...

  7. Python: 无参数的函数装饰器

    写带参数的函数装饰器最纠结的是需要包好多层,最外层是接收参数的函数,它返回一个接收函数的的函数.但这样有个问题是,最终包装出来的装饰器必须加()调用一下,即使没有参数也需要这样做,因为调用这个最外层函 ...

  8. Python带参数的函数装饰器

    # -*- coding: utf-8 -*- # author:baoshan # 带参数的函数装饰器 def say_hello(country): def wrapper(func): def ...

  9. python3 速查参考- python基础 7 -> 函数编程之 装饰器、生成器

    装饰器 1.速查笔记 #-- 函数装饰器:是它后边的函数的运行时的声明 由@符号以及后边紧跟的"元函数"(metafunction)组成 @staticmethod def sme ...

随机推荐

  1. Redis与高级语言内置的数据结构相比的异同及优势

    相关链接: 为什么要用redis而不用map做缓存? Redis的数据结构及应用场景 Redis缓存和直接使用内存的比较 Java自带的数据结构(如HashMap,BitSet等)做缓存和NoSQL( ...

  2. virtualbox+vagrant学习-4-Vagrantfile-2-Configuration Version

    Configuration Version 配置版本是vagrant 1.1+能够与vagrant 1.0保持向后兼容的机制.同时引入了引人注目的新特性和配置选项. 如果你运行了vagrant ini ...

  3. JAVA开发微信支付-公众号支付/微信浏览器支付(JSAPI)

    写这篇文章的目的有2个,一是自己的项目刚开发完微信支付功能,趁热回个炉温习一下,二也是帮助像我这样对微信支付不熟悉,反复看了多天文档还是一知半解,原理都没摸清,更不要说实现了.本以为网上的微信开发教程 ...

  4. (转)使用 Nmon 监控 Linux 的系统性能

    看到一个使用Nmon的文章,写的很基础,适合新手,转载之.下面是原文的信息: 作者:Hitesh Jethva 译者:sonofelice 校对:wxy 传送门:linux.cn/article-68 ...

  5. P1877 [HAOI2012]音量调节

    题目描述 一个吉他手准备参加一场演出.他不喜欢在演出时始终使用同一个音量,所以他决定每一首歌之前他都需要改变一次音量.在演出开始之前,他已经做好一个列表,里面写着每首歌开始之前他想要改变的音量是多少. ...

  6. P1441 砝码称重

    题目描述 现有n个砝码,重量分别为a1,a2,a3,……,an,在去掉m个砝码后,问最多能称量出多少不同的重量(不包括0). 输入输出格式 输入格式: 输入文件weight.in的第1行为有两个整数n ...

  7. RabbitMQ如何保证发送端消息的可靠投递

    消息发布者向RabbitMQ进行消息投递时默认情况下是不返回发布者该条消息在broker中的状态的,也就是说发布者不知道这条消息是否真的抵达RabbitMQ的broker之上,也因此会发生消息丢失的情 ...

  8. matlab 基于 libsvm工具箱的svm分类遇到的问题与解决

    最近在做基于无线感知的身份识别这个工作,在后期数据处理阶段,需要使用二分类的方法进行训练模型.本身使用matlab做,所以看了一下网上很多都是使用libsvm这个工具箱,就去下载了,既然用到了想着就把 ...

  9. Linux命令学习笔记2(mysql安装和mysql-python安装)

    linux下 强制安装 rpm安装包(切换到root用户):  rpm -ivh bluefish-shared-data-2.2.7-1.el6.noarch.rpm --nodeps --forc ...

  10. 19-[模块]-xml

    1.xml协议 xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融 ...