函数进阶以及知识点补充

主要内容

  1,通用装饰器回顾

  2,函数的有用信息

  3,带参数的装饰器

  4,多个装饰器同时装饰一个函数

一,通用装饰器的回顾

  开闭原则:对增加功能开放,对修改代码封闭

  装饰器的作用:在不改变源代码的基础上给一个函数增加功能

  通用装饰器的写法:

def wrapper(func):
    def inner(*args, **kwargs):
        print("目标函数执行之前要执行的内容")
        ret = func(*args, **kwargs)
        print("目标函数执行之后要执行的内容")
        return ret
    return inner


@wrapper
def func1():
    print("我爱祖国")


func1()

 执行过程:

1,程序从上向下,当执行到@wrapper的时候,把函数作为参数传递给wrapper函数,得到inner函数,重新赋值给func1

2,当执行到func1的时候,我们实际执行的是inner函数.inner函数会执行目标函数之前的代码,然后在执行你的目标函数,执行完目标函数最后执行的是目标函数之后的代码

 

二,函数的有用信息

  1,如何给函数添加注释

def chi(food, drink):
    '''
    这里是函数的注释,先写一下当前函数是干什么的,比如我们这个函数就是一个吃
    :param food: 参数food是社么意思
    :param drink: 参数drink是什么意思
    :return: 返回的值是什么
    '''
    print(food, drink)
    return 'very good'

 

def chi(food, drink):
    '''
    这里是函数的注释,先写一下当前函数是干什么的,比如我们这个函数就是一个吃
    :param food: 参数food是社么意思
    :param drink: 参数drink是什么意思
    :return: 返回的值是什么
    '''
    print(food, drink)
    '''
    这个可以获取到么
    '''
    print(chi.__doc__)  # 获取函数的文档注释
    print(chi.__name__)  # 获取到函数名称
    return 'very good'

chi('吃嘛嘛香', '我不想吃')
print(chi.__doc__)
print(chi.__name__)

   函数名.__name__可以查看函数的名字

  函数名.__doc__可以查看函数的文档注释

 

接下来看下被装饰器装饰之后的函数名:

def wrapper(func):
    def inner(*args, **kwargs):
        print('目标函数之前执行的内容')
        ret = func(*args, **kwargs)
        print('目标函数之后执行的内容')
        return ret
    return inner


@wrapper
def func1():
    print("我爱我的祖国")


func1()
print(func1.__name__)  # inner
# 分析:虽然执行的是func1函数,但是装饰器经过func1 = wrapper(func1),返回的值是inner,所以实际执行的是inner

   问题来了,我们虽然访问的是func1函数.但实际上执行的是inner函数,这样就会给下游程序员带来困惑,之前不是一直执行的是func1么,为什么突然换成了inner.接下来的实现方案:

from functools import wraps


def wrapper(func):
    @wraps(func)
    def inner(*args, **kwargs):
        print("目标函数执行之前执行的内容")
        ret = func(*args, **kwargs)
        print('目标函数执行之后执行的内容')
        return ret
    return inner


@wrapper
def func1():
    print("我爱我的祖国")


func1()
print(func1.__name__)  # func1

 PS: *args和**kwargs什么时候打散,什么时候聚合

  1,接收参数的时候是聚合,参数声明

  2,传递参数的时候是打散,给函数传递实参

def wrapper(func):
    def inner(*args, **kwargs):  # 这里是聚合
        print("目标函数执行之前执行的内容")
        ret = func(*args, **kwargs)  # 这里是打散
        print("目标函数执行之后执行的内容")
        return ret
    return inner

 三,装饰器传参

  给装饰器设置一个开关,可以控制装饰器是否运行

from functools import wraps

def wrapper_out(flag):
    def wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs):
            if flag:
                print('目标函数执行之前执行的内容')
                ret = func(*args, **kwargs)
                print('目标函数执行之后执行的内容')
                return ret
            else:
                ret = func(*args, **kwargs)
                return ret
        return inner
    return wrapper


@wrapper_out(False)
def func1():
    print("我爱我的祖国")

func1()

 

四,多个装饰器装饰同一个函数

def wrapper(func):
    def inner(*args, **kwargs):
        print("目标函数执行之前的内容1")
        ret = func(*args, **kwargs)
        print("目标函数执行之后的内容2")
        return ret
    return inner


def wrapper1(func):
    def inner(*args, **kwargs):
        print("目标函数执行之前的内容3")
        ret = func(*args, **kwargs)
        print("目标函数执行之后的内容4")
        return ret
    return inner

@wrapper1
@wrapper
def func1():
    print("我爱我的祖国")


func1()
# 结果
# 目标函数执行之前的内容3
# 目标函数执行之前的内容1
# 我爱我的祖国
# 目标函数执行之后的内容2
# 目标函数执行之后的内容4

   执行顺序:首先@wrapper装饰起来,然后获取到一个新函数是wrapper中的inner.然后执行@wrapper1.这个时候wrapper1装饰的就是wrapper中的inner了.所以,执行顺序就是像:第二层装饰器前(第一层装饰器前(目标)第一层装饰器后)第二层装饰器后.程序从左往右执行起来就是我们看到的结果

 

小知识点补充:

枚举,编码,解码
lst = ['周杰伦', '李嘉诚', '奥特曼', '小怪兽']
for index, element in enumerate(lst):
    print(index, element)

# 0 周杰伦
# 1 李嘉诚
# 2 奥特曼
# 3 小怪兽

s = "明天就要过端午节了"
bys = s.encode('utf-8')
print(bys)
#b'\xe6\x98\x8e\xe5\xa4\xa9\xe5\xb0\xb1\xe8\xa6\x81\xe8\xbf\x87\xe7\xab\xaf\xe5\x8d\x88\xe8\x8a\x82\xe4\xba\x86'

s1 = bys.decode('utf-8')
print(s1)
# 明天就要过端午节了
View Code

 

posted @ 2018-06-15 13:39  猴里吧唧  阅读(123)  评论(0)    收藏  举报