Python学习 day12

一、@wraps

__name__    查看函数的名字

__doc__   查看函数的文档字符串

例:

def func(arg):
    """
    这是一个测试函数,这里是函数说明
    :param arg: 参数说明
    :return: 返回值说明
    """
    return arg


print(func.__name__)
print(func.__doc__)

结果:

但是,经过装饰器装饰的函数,我们知道虽然调用与原来一致,但原函数名实际指向的却是装饰器中的inner函数,所以在调用__name__和__doc__时,得到的结果,如下:

def wrapper(func):
    def inner(*args, **kwargs):
        """
        这是一个装饰器内部函数,对原函数进行装饰
        :param args: 原函数中的位置传参
        :param kwargs: 原函数中的按关键字传参
        :return: 返回原函数执行后的结果
        """
        print("在原函数之前")
        ret = func(*args, **kwargs)
        print("在原函数之后")
        return ret
    return inner


@wrapper
def test(arg):
    """
    这是一个测试函数,这里是函数说明
    :param arg: 参数说明
    :return: 返回值说明
    """
    return arg


print(test.__name__)
print(test.__doc__)

结果:

可以看到,被装饰的函数调用__name__和__doc__得到的不再是原函数的名称和文档字符串

为了解决这个问题,我们引入wraps装饰inner函数,就可以正常获取元函数的函数名和文档字符串了,如下:

from functools import wraps


def wrapper(func):
    @wraps(func)  # 用wraps装饰inner函数
    def inner(*args, **kwargs):
        """
        这是一个装饰器内部函数,对原函数进行装饰
        :param args: 原函数中的位置传参
        :param kwargs: 原函数中的按关键字传参
        :return: 返回原函数执行后的结果
        """
        print("在原函数之前")
        ret = func(*args, **kwargs)
        print("在原函数之后")
        return ret
    return inner


@wrapper
def test(arg):
    """
    这是一个测试函数,这里是函数说明
    :param arg: 参数说明
    :return: 返回值说明
    """
    return arg


print(test.__name__)
print(test.__doc__)

执行以上代码,得到:

二、带参数的装饰器

 在有些情况下,需要使用带参数的装饰器,把外部的变量值传入装饰器中,进行相关操作。

举例:如有一种情况,项目经理需要测试每个人设计的函数的执行时间,以此来对每个人的函数进行评测,这时就需要增加函数执行的计时功能,需要用到装饰器。在评测结束后,项目经理又要求将计时功能去掉,这如果把装饰器再一个个去除就会非常麻烦,因此需要一种变通的方法能保证需要的时候增加装饰器,不需要时去掉。

就这个例子设计一个装饰器,我们有如下方法:

import time

FLAG = True  # 标志位


def timmer_out(FLAG):
    def timmer(func):
        def inner(*args, **kwargs):
            if FLAG:  # FLAG为True时,增加计时功能
                start = time.time()
                ret = func(*args, **kwargs)
                end = time.time()
                print(end - start)
                return ret
            else:  # False时不装饰
                return func(*args, **kwargs)
        return inner
    return timmer


def func1():
    print("执行func1")
    time.sleep(3)
    print("func1结束")


@timmer_out(FLAG)  # 语法糖,实际如下面func1
def func2():
    print("执行func2")
    time.sleep(5)
    print("func2结束")


t = timmer_out(FLAG)
func1 = t(func1)
func1()
func2()

结果:

若FLAG=False,结果:

可以看到,通过控制FLAG的值就可以控制是否给原函数增加装饰,解决了问题。

其实timmer_out函数就做了一个利用闭包传参的功能,若没有timmer_out这个外部函数,里面inner想使用全局变量FLAG的值在python中也是可以的,但这样的用法不是程序设计推荐的,不如由外部函数timmer_out传入更规范。

三、多个装饰器装饰一个函数

多个装饰器装饰一个函数依然类似java中的过滤器和拦截器,与aop思想一致,因多个装饰器都对函数有增加功能,那执行的顺序是什么呢,如:

def wrapper1(func):
    def inner(*args, **kwargs):
        print("-------wrapper1在函数调用前--------")
        ret = func(*args, **kwargs)
        print("-------wrapper1在函数调用后--------")
        return ret
    return inner


def wrapper2(func):
    def inner(*args, **kwargs):
        print("-------wrapper2在函数调用前--------")
        ret = func(*args, **kwargs)
        print("-------wrapper2在函数调用后--------")
        return ret
    return inner


def wrapper3(func):
    def inner(*args, **kwargs):
        print("-------wrapper3在函数调用前--------")
        ret = func(*args, **kwargs)
        print("-------wrapper3在函数调用后--------")
        return ret
    return inner


@wrapper2
@wrapper1
@wrapper3
def func():
    print("我是被装饰函数")


func()

结果:

可看到,装饰器的执行顺序是根据装饰顺序来的:2-1-3-func-3-1-2

四、零散知识点

1、函数的注释

在python中写的函数,也有函数注释,类似java的方法注释,用于说明函数的主要功能,参数和返回值。

具体写法:

def func(arg):
    """
    这是一个测试函数,这里是函数说明
    :param arg: 参数说明
    :return: 返回值说明
    """
    return arg

在pycharm中函数下面直接输入三个”工具会自动显示函数注释的内容

2、os.path.getsize()

从os模块引入getsize()函数,用于判断文件大小。例:

import os
print(os.path.getsize('test'))  # 获取test文件的大小,单位byte

五、其他

课程老师推荐了两本书《Python核心编程》、《流畅的python》,可以买来看看。

 

posted @ 2018-10-17 17:43  蜜酥糖糖糖丶  阅读(140)  评论(0编辑  收藏  举报