day04-装饰器

一、装饰器定义

1)装饰器:本质是函数。

2)功能:用来装饰其他函数,顾名思义就是,为其他的函数添加附件功能的。

二、原则

1)不能修改被装饰函数的源代码

2)不能修改被装饰函数的调用方式

如果你写的这个程序在生产环境下已经运行了,如果修改别人的源代码或者修改别人的调用方式,那么出了问题,后果可想而知

三、实现装饰器知识储备

1)函数即"变量"

2)高阶函数

3)嵌套函数

最终: 高阶函数+嵌套函数 => 装饰器

3.1 函数即变量

1)python的内存机制

#变量

x = 1

#函数

def test():

pass

以上一个变量一个函数在内存中的表现形式如下图:

在python解释器中,有一个概念叫做引用基数,比方说,x=1,它会先在内存当中把1这个值实实在在的存放下来,这个x其实就是1的门牌号,也是对1的一次引用。python什么时候把这个1这个屋子清空呐?它会等到1所对应的门牌号都没有了,就会把1这里面的东西给清掉,这个也是python的内存回收机制,就是靠这种方式回收的。

2)del清理

那我们用什么清理呐?用del去清理门牌号,就是对1的值引用的变量,del  x就表示清理掉1对应的x的门派号。如果x没有被del,则x永远不还被删除,除非程序结束了,不然永远不会被删除。del删除的不是1,只是把门牌号x删除了,只是定期刷新时,发现1没有被其他门牌号引用了,才会被清掉。

3)函数在内存的表现形式

①bar函数在foo函数之后定义

#bar函数在foo函数之后定义
def foo():
    print("in the foo")
    bar()

def bar():
    print("in the bar")

foo()

#输出

in the foo

in the bar

②bar函数是在foo函数之前定义

# bar函数是在foo函数之前定义
def bar():
    print("in the bar")

def foo():
    print("in the foo")
    bar()

foo()

#输出

in the foo

in the bar

显然,两种写法效果是一样的,那我们来看看第三种情况。

③bar函数在foo函数调用之后声明

# bar函数在foo函数调用之后声明
def foo():
    print("in the foo")
    bar()

foo()

def bar():
    print("in the bar")

#输出

Traceback (most recent call last):

in the foo

File "D:/PycharmProjects/pyhomework/day4/装饰器/函数即变量.py", line 31, in <module>

foo()

File "D:/PycharmProjects/pyhomework/day4/装饰器/函数即变量.py", line 29, in foo

bar()

NameError: name ‘bar‘ is not defined  #bar函数没有定义

 

3.2 高阶函数

实现高阶函数有两个条件:

1)把一个函数名当做实参传给另外一个函数

2)返回值中包含函数名

1、把一个函数名当做实参传给另外一个函数

作用:在不修改被装饰函数源代码的情况下为其添加功能

import  time
def bar():
    time.sleep(3)
    print("in the bar")

def test1(func):
    print(func)         #相当于print(bar) 函数的内存地址
    start_time = time.time()
    func()              #相当于bar() 进入函数内部执行
    stop_time = time.time()
    print("the func run the is %s"%(stop_time-start_time))
#没有修改bar的代码
test1(bar)  #把bar函数名当做实参传到test1中

  

#输出

<function bar at 0x0000000000A7D378>  #bar函数的内存地址

in the bar                               #函数值

the func run the is 2.9912972450256348

2、返回值中包括函数名

作用:不修改函数调用方式

import  time

def bar():
    time.sleep(3)
    print("in the bar")

def test2(func):
    print(func)
    return func   #返回函数的内存地址

#调用test2函数
bar = test2(bar)   #重新给bar赋值,打印内存地址(内存地址加上小括号就能打印函数值)
bar()  #bar函数调用方式不变,实现装饰器的功能

 

相当于@bar

#输出

<function bar at 0x0000000000B6D378>  #打印bar函数的内存地址

in the bar

3.3 嵌套函数

1、定义

在一个函数的函数体内,用def 去声明一个函数,而不是去调用其他函数,称为嵌套函数。

嵌套函数例子:

def foo():
    print("in the foo")
    def bar():  #在foo函数体内,用def声明一个函数
        print("in the bar")
    bar()
#调用foo函数
foo()

 

#输出

in the foo

in the bar

下面这种情况是不是嵌套函数? 

def bar():
    print("in the bar")

def foo():
    print("in the foo")
    bar()  #调用bar函数

foo()

很显然不是,因为只是调用了bar函数,没有用def去声明一个函数。

  

局部作用域和全局作用域的访问顺序

#局部作用域和全局作用域的访问顺序
x=0
def grandpa():
    x=1
    def dad():
        x=2
        def son():
            x=3
            print(x)
        son()
    dad()
#调用grandpa
grandpa()

很显然最后输出的是3,这个说明作用域:只能是从里往外找,一层一层的的找。

四、装饰器实现

4.1 定义

装饰器实现的条件:高阶函数+嵌套函数 =》装饰器

import time

#定义内置函数
def timmer(func):  #timmer(test1) func=test1
    def deco():
        start_time = time.time()
        func()   #run test1()
        stop_time = time.time()
        print("the func run time is %s"%(stop_time-start_time))
    return deco           #返回deco的内存地址

#装饰test1函数
@timmer
# 相当于test1 = timmer(test1)      test1(),调用deco的内存值。同时也有定义一个test1的变量
def test1():
    time.sleep(3)
    print("in the test1")

#直接执行test1函数
test1()

#输出

in the test1

the func run time is 3.0002999305725098

执行步骤:

  1. 执行timmer函数,timmer(test1) 返回值赋值给test1变量,即test1=timmer(test1)
  2. 此时的test1的值是执行timmer函数返回值deco,即test1=deco
  3. 所以执行test1,其实就是执行的是deco函数,test1()其实就是执行deco函数。

4.2 执行函数带参数

import time

def timmer(func):  #timmer(test2) func=test2
    def deco():
        start_time = time.time()
        func()   #run test2()
        stop_time = time.time()
        print("the func run time is %s"%(stop_time-start_time))

    return deco

@timmer
def test2(name,age):
    print("name:%s,age:%s"%(name,age))

test2()

  

#输出

Traceback (most recent call last):

File "D:/PycharmProjects/pyhomework/day4/装饰器/装饰器高潮.py", line 23, in <module>

test2()

File "D:/PycharmProjects/pyhomework/day4/装饰器/装饰器高潮.py", line 8, in deco

func()   #run test1()

TypeError: test2() missing 2 required positional arguments: ‘name‘ and ‘age‘ #缺少传入name和age参数

 

很显然是错误的。因为这边执行的test2函数其实就是执行的deco函数,deco函数体内的func()其实就是执行test2函数,但是,test2需要传入name和age两个参数,所以报错。那怎么解决呢?

传入确定参数:

import time

def timmer(func):  #timmer(test1) func=test1
    def deco(name,age):
        start_time = time.time()
        func(name,age)   #run test2()
        stop_time = time.time()
        print("the func run time is %s"%(stop_time-start_time))

    return deco

@timmer
def test2(name,age):
    print("name:%s,age:%s"%(name,age))

test2(‘zhou‘,22)

  

不能确定传入几个参数,所以我们用非固定参数传参。代码如下:

import time

def timmer(func):  #timmer(test1) func=test1
    def deco(*args,**kwargs):  #传入非固定参数
        start_time = time.time()
        func(*args,**kwargs)   #传入非固定参数
        stop_time = time.time()
        print("the func run time is %s"%(stop_time-start_time))

    return deco

#不带参数
@timmer  # 相当于test1 = timmer(test1)
def test1():
    time.sleep(3)
    print("in the test1")

#带参数
@timmer
def test2(name,age):
    print("name:%s,age:%s"%(name,age))
#调用
test1()
test2("Alex",22)

  

#输出

#test1

in the test1

the func run time is 3.0010883808135986

#test2

name:Alex,age:22

the func run time is 0.0  #test2

4.3 执行函数有返回值

def timmer(func):  #timmer(test1) func=test1
    def deco(*args,**kwargs):
        res = func(*args,**kwargs) #这边传入函数结果赋给res
        return res   # 返回res
    return deco

@timmer
def test1():  # test1 =  timmer(test1)
    print("in the test1")
    return "from the test1" #执行函数test1有返回值

res = test1()
print(res)

  

#输出

in the test1

from the test1

通过上面的例子,可以看出,其实就是在内置函数中把传入参数的执行结果赋给res,然后再返回res变量。

 

4.4带参数装饰器

之前我们的装饰器都是没有带参数的,其实我们已经能解决90%的问题了,但是如果说有一种情况:就是在你访问不通页面时,你用的验证的方式来源不同,这时你该怎么办?

 

#本地验证
user,passwd = "zhouqiongjie","abc123"

def auth(auth_type):  #传递装饰器的参数
    print("auth func:",auth_type)
    def outer_wrapper(func):   # 将被装饰的函数作为参数传递进来
        def wrapper(*args,**kwargs):  #将被装饰函数的参数传递进来
            print("wrapper func args:",*args,**kwargs)
            username = input("Username:").strip()
            password = input("Password:").strip()
            if auth_type == "local":
                if user == username and passwd == password:
                    print("\033[32mUser has passed authentication\033[0m")
                    res = func(*args,**kwargs)
                    print("--after authentication")
                    return res
                else:
                    exit("Invalid username or password")
            elif auth_type == "ldap":
                pass
        return wrapper
    return outer_wrapper

def index():
    print("welcome to index page")

@auth(auth_type="local")  #带参数装饰器
def home():
    print("welcome to home page")
    return "from home"

@auth(auth_type="ldap")   #带参数装饰器
def bbs():
    print("welcome  to bbs page")

index()
print(home())
bbs()

  

上面的例子可以看出,执行步骤:

1)        outer_wrapper = auth(auth_type="local")

2)        home = outer_wrapper(home)

3)home()

所以这个函数的作用分别是:

1)        auth(auth_type) 传递装饰器的参数

2)        outer_wrapper(func) 把函数当做实参传递进来

3)wrapper(*args,**kwargs) 真正执行装饰的函数

  

时间: 2024-07-28 13:47:44

day04-装饰器的相关文章

python——迭代器、生成器、装饰器

迭代器 迭代器规则 迭代:重复做一些事很多次,就像在循环中那样. 不仅可以对字典和序列进行迭代,还可以对其他对象进行迭代:只要该对象实现了__iter__方法. __iter__方法会返回一个迭代器(iterator),所谓的迭代器就是具有next方法(这个方法在调用时不需要任何参数)的对象.在调用next方法时,迭代器会返回他的下一个值.如果next方法被调用,但迭代器没有值可以返回,就会引发一个StopIteration异常. 注意:迭代器规则在3.0中有一些变化.在新的规则中,迭代器对象应

Python 装饰器的形成过程

装饰器  定义:本质是函数,(装饰其他函数),即为其他函数添加附加功能.  原则: 1.不能修改被装饰的函数的源代码:            2.不能修改被装饰的函数的调用方式. 实现装饰器知识储备:   1. 函数即'变量'           2. 高阶函数       a. 把一个函数名当作实参传递给另一个函数(在不修改被装饰函数源代码的前提下为其添加新功能)       b. 返回值中包含函数名(不修改函数的调用方式)   3. 嵌套函数 高阶函数 + 嵌套函数 (组成)--> 装饰器

Day4 - 迭代器&amp;生成器、装饰器、Json &amp; pickle 数据序列化、软件目录结构规范

---恢复内容开始--- 本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 需求:列表a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],要求把列表里的每个值加1 1 a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 2 b = [] 3 for i in a: 4 b.append(i+1) 5 a = b 6 print(a) 普通青

python3 装饰器

看廖雪峰官网的python3装饰器有感 装饰器即将一个函数作为变量在新的函数中调用此函数. 作业: 能否写出一个@log的decorator,使它既支持: @logdef f():     pass 又支持: @log('execute')def f():     pass      例1: import functools import time def log(*args,**kwargs):     # *args 是个元组     if args and isinstance(args,

day14 带函数的装饰器、多个装饰器装饰一个函数

一.带参数的装饰器:------开关 __author__ = 'Administrator' F=True def outer(F): def wap(fun):#gg def inner(*args,**kwargs): if F: print("inner before") ret=fun(*args,**kwargs)#gg() print("inner after") else: ret=fun(*args,**kwargs) return ret ret

Python 装饰器

一.定义 器即函数 装饰即修饰,意指为其他函数添加新功能 装饰器本身可以是任意可调用对象,被装饰的对象本身也可以是任意可调用对象 实现装饰器: 装饰器=高阶函数+函数嵌套+闭包 二.原则: 1 .开放封闭原则:对扩展是开放的,对修改是封闭 2.1 装饰器的遵循的原则:1 不修改被装饰对象的源代码 2 不修改被调用对象的调用方式 三.目的 装饰器的目的是:在遵循1和2原则的前提,为其他新功能函数添加 四.定义位置 @装饰器名,必须写在被装饰对象的正上方,并且是单独一行 import time de

装饰器、生成器、迭代器

装饰器的前奏 装饰器:本质是函数 功能:就是装饰成其他函数  就是为其他函数添加附加功能的 高阶函数+嵌套函数=装饰器 原则:1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式 总结一句话:装饰器对被装饰的函数是完全透明的 实现装饰器的只是储备: 1.函数名即"变量"   将函数体赋值给变量   和内存回收机制一样 2.高阶函数 2.1.把函数名作为实参传递给形参(可返回被修饰函数的地址)(不修改源代码的情况可添加新的功能) 2.2返回值中包含函数地址(不修改函数的调

python 装饰器的用法

为什么要使用装饰器? 在不改变原函数功能的情况,为了添加新的功能 我们可以在函数运行前后给函数添加新的功能 1 def outer(func): 2 #fun()等于原f1函数 3 def inner(): 4 print('ccccc') 5 r=func() 6 print('dddd') 7 return r 8 return inner 9 @outer 10 #@outer代表运行了2个步骤:1.将f1作为参数运行outer函数,2.新函数f1=inner() 11 def f1():

Python装饰器

1.最简单的例子 1 #coding:utf8 2 3 def b(z): 4 print u'装饰器' 5 def func(*args,**kw): 6 print '111' 7 return z(*args,**kw) 8 return func 9 10 @b 11 def a(x): 12 print x 13 print u'函数A' 14 15 a('y')

python3_装饰器_异常处理

装饰器: def auth(func):     def wrapper(name):                     如果函数带参数,要加在这里         user=raw_input("input passwd:").strip()         if user=='test':             print "welcome login"             func(name)              如果函数带参数,要加在这里