Python自学之路之day12-装饰器

介绍装饰器之前,我们先了解下以下函数打印结果。

1def base():
    print("我是base函数")
def bar():
    print("我是bar函数")

bar = base
bar()

打印结果:
我是base函数

2def func():
    def inner():
        print("我是inner函数")
    return inner

v = func()
print(v)

打印结果:
(<function func.<locals>.inner at 0x00000269313A0AE8>)打印inner函数内存地址

3)
def func(arg):
    def inner():
        print(arg)
    return inner

v1 = func(1)
v2 = func(2)

4)
def func(arg):
    def inner():
        arg()
    return inner

def fn1():
    print("我是fn1函数")

v1 = func(fn1)
v1()

5)
def func(arg):   # arg = f1
    def inner():
        arg()    # 等于执行f1函数
    return inner
def f1():
    print(123)
    return 666

v1 = func(f1) #v1 == inner函数
result = v1() # 执行inner函数,inner函数包含arg(f1函数)函数执行,打印123,返回666,但是666并没变量接收
print(result) #  接收返回值,该返回值为inner的返回值,为None
打印结果:
123
None

6def func(arg):
    def inner():
        return arg()
    return inner

def f1():
    print(123)
    return 666

v1 = func(f1) # v1 == inner
result = v1() # 执行inner函数,inner函数的返回值为arg(f1)函数的执行,打印123,并把666返回给inner,result == 666
print(result)

二、装饰器

## 装饰器
def func(arg):
    def inner():
        print('before')
        v = arg()
        print('after')
        return v
    return inner

def index():
    print('123')
    return '666'

#1、
# v1 = index()  # 执行index函数,打印123,返回666

#2、
# v2 = func(index) # 执行func函数,返回值为inner函数,v2 == inner,此时arg == index,指向index函数地址
# index = 666      # index重新赋值为666,注意:虽然index被重新赋值,但是index函数对应的地址,并没有销毁,arg对应的就是index函数的内存地址
# v3 = v2()        # v3等于inner函数的返回值。执行inner函数,首先会打印"before",v = arg(),arg = index,所以相当于执行index函数,会打印123,并将666赋值给v,接着打印after,inner函数返回v
# print(v3)        # 根据上面分析,v3等于inner函数的返回值,inner函数返回值为v,v == 666,因此最后会打印666
## 打印结果
"""
before
123
after
666
"""
#3、
v4 = func(index) # 执行func函数,返回值为inner函数,v4 == inner,此时arg == index,指向index函数地址
index = v4       # 把v4(inner)赋值给index,这时index = inner,注意,此时的index,与之前的index并不是一个函数
index()          # 执行index函数,相当于执行inner函数,首先打印"before", v = arg():等于是执行之前的index函数,此时会打印123,并把index的函数返回值赋值给v,随后打印"after",inner返回值为v
## 打印结果
"""
before
123
after
"""
#4、根据3中的分析,可以简写为以下模式。
index = func(index)
index()

 最终装饰器成型:

def func(arg):
    def inner():
        print('before')
        v = arg()
        print('after')
        return v
    return inner
# 第一步:执行func函数并将下面的函数参数传递,相当于:func(index)
# 第二步:将func的返回值重新赋值给下面的函数名。 index = func(index)
@func
def index():
    print('123')
    return '666'

打印结果:
before
123
after

装饰器总结:

目的:在不改变原函数的基础上,在函数执行前后自定义功能。

# 装饰器的编写
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 外层函数(参数): 
    def 内层函数(*args,**kwargs):
        return 参数(*args,**kwargs)
    return 内层函数

装饰器应用格式:

@外层函数
def index():
    pass

index()

 三、带参数装饰器

# ################## 普通装饰器 #####################
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(9)
def index():
    pass

分析:

def x(counter):
    def wrapper(func):
        def inner(*args,**kwargs):
            data = func(*args,**kwargs) # 执行原函数并获取返回值
            return data
        return inner 
    return wrapper 

# 第一步:执行 v1 = x(9)
# 第二步:ret = v1(index)
# 第三步:index = ret 
@x(9)
def index():
    pass

练习1:

# 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,把每次结果添加到列表中,最终返回列表。
def xxx(counter):
    print('x函数')
    def wrapper(func):
        print('wrapper函数')
        def inner(*args,**kwargs):
            v = []
            for i in range(counter):
                data = func(*args,**kwargs) # 执行原函数并获取返回值
                v.append(data)
            return v
        return inner
    return wrapper

@xxx(5)
def index():
    return 8

v = index()
print(v)

练习2:

# 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,并返回最后一次执行的结果
def xxx(counter):
    print('x函数')
    def wrapper(func):
        print('wrapper函数')
        def inner(*args,**kwargs):
            for i in range(counter):
                data = func(*args,**kwargs) # 执行原函数并获取返回值
            return data
        return inner
    return wrapper

@xxx(5)
def index():
    return 8

v = index()
print(v)

模板:

def x(counter):
    print('x函数')
    def wrapper(func):
        print('wrapper函数')
        def inner(*args,**kwargs):
            if counter:
                return 123
            return func(*args,**kwargs)
        return inner
    return wrapper

@x(True)
def fun990():
    pass

@x(False)
def func10():
    pass

练习题3:

# 请为以下函数编写一个装饰器,添加上装饰器后可以实现:执行 read_userinfo 函时,先检查文件路径是否存在,如果存在则执行后,如果不存在则 输入文件路径不存在,并且不再执行read_userinfo函数体中的内容,再讲 content 变量赋值给None。


def read_userinfo(path):
    file_obj = open(path,mode='r',encoding='utf-8')
    data = file_obj.read()
    file_obj.close()
    return data

content = read_userinfo('文件路径')

答案:
import os
def warper(fn):
    def inner(*agrs,**kwargs):
        if not os.path.exists("../day13"):
            print("路径不存在")
            return None
        v = fn(*agrs,**kwargs)
        return v
    return inner
@warper
def read_userinfo(path):
    file_obj = open(path,mode='r',encoding='utf-8')
    data = file_obj.read()
    file_obj.close()
    return data

content = read_userinfo('../day13/作业.py')
print(content)

 

posted @ 2019-08-27 14:41  小哥boy  阅读(56)  评论(0)    收藏  举报