美文网首页程序员
Python干货-装饰器与偏函数

Python干货-装饰器与偏函数

作者: 东南有大树 | 来源:发表于2018-10-30 16:02 被阅读20次

装饰器

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。

概括的讲,装饰器的作用就是为已经存在的函数或对象添加额外的功能。

举个简单的栗子:

# 定义一个记录日志用来调试的函数
def debug(func):
    def wrapper():
        print("[DEBUG]: enter {}()".format(func.__name__))
        return func()
    return wrapper

# 定义一个say_hello函数
def say_hello():
    print("hello!")

# 调用debug函数并将say_hello函数当作参数传入,返回的是wrapper函数
hello = debug(say_hello)
# 执行wrapper函数
hello()
[DEBUG]: enter say_hello()
hello!

debug函数对say_hello函数进行了包装,也就是增加了更多功能,实际上,debug函数已经是一个装饰器了

更加简单的写法是使用语法糖语法@debug,示例如下:

# 定义一个记录日志用来调试的函数
def debug(func):
    def wrapper():
        print("[DEBUG]: enter {}()".format(func.__name__))
        return func()
    return wrapper

@debug
# 定义一个say_hello函数
def say_hello():
    print("hello!")

say_hello()
[DEBUG]: enter say_hello()
hello!

@debug的效果与hello = debug(say_hello)是一样的,是不是很惊艳!

关于参数问题

定装饰器函数wrapper中调用了原函数say_hello,但如果原函数有参数,或者有很多参数的时候,可以利用python多参数形式,如下:

# 定义一个记录日志用来调试的函数
def debug(func):
    def wrapper(*args, **kwargs):
        print("[DEBUG]: enter {}()".format(func.__name__))
        return func(*args, **kwargs)
    return wrapper

@debug
# 定义一个say_hello函数
def say_hello(name, world):
    print(world, name)

say_hello('Jack', 'hello')
[DEBUG]: enter say_hello()
hello Jack

通过使用*args, **kwargs这得传参数形式,支持元组形式或字典形式的传值结构,不管是有参数还是多个参数,都可以很好的应对

带参数的装饰器

定义一个可以指定日志输出级别的“日志输出装饰器函数”

def logging(level):
    def wrapper(func):
        def inner_wrapper(*args, **kwargs):
            print("[{level}]: enter function {func}()".format(
                level=level,
                func=func.__name__))
            return func(*args, **kwargs)
        return inner_wrapper
    return wrapper

@logging(level='INFO')
def say(something):
    print("say {}!".format(something))

# 如果没有使用@语法,等同于
# say = logging(level='INFO')(say)

@logging(level='DEBUG')
def do(something):
    print("do {}...".format(something))

say('hello')
do("my work")
[INFO]: enter function say()
say hello!
[DEBUG]: enter function do()
do my work...

解析:

当带参数的装饰器被打在某个函数上时,比如@logging(level='DEBUG'),它其实是一个函数,会马上被执行

而被执行的logging函数返回的结果,才是一个装饰器函数O(∩_∩)O哈哈~

偏函数

偏函数可以设定函数的默认行为,示例如下:

num = int('12345')
print(num)
12345

在默认情况下,int()函数会将字符串数字转换成十进制的数据,便也可以通过设定参数来让int()函数将其转换成八进制数字,如下:

num = int('12345', base=8)
print(num)
5349

那如何改变int()函数的默认行为呢?

# 首先导入 functools 模块
import functools

# 定义一个默认转换为二进制的int函数
int2 = functools.partial(int, base=2)
# 调用 
int2('10110101')
181

functools.partial的作用就是将固定一个函数的默认行为,从而简化之后的使用

来看看关于它的描述:

Init signature: functools.partial(self, /, *args, **kwargs)
Docstring:     
partial(func, *args, **keywords) - new function with partial application
of the given arguments and keywords.

所以,这个方法可以接收函数、*args、**kwargs这些对象

这里的base=2是字典结构的参数

max2 = functools.partial(max, 10)
max2(5, 6, 7)  # 相当于max2(10, 5, 6, 7)
10

小结
当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。

相关文章

  • Python干货-装饰器与偏函数

    装饰器 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返...

  • Python ☞ day 5

    Python学习笔记之 装饰器& 偏函数 & 异常处理 & 断言 & 文件读写 &编码与解码 装饰器 概念:是一个...

  • python四装饰器与偏函数

    装饰器 定义: 假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数...

  • 笨笨的学pythonDay06

    接着昨天未学完的函数,还有个偏函数和装饰器,先说一下偏函数,装饰器没有看明白 1.偏函数 偏函数可以通过将函数参数...

  • Python:6.函数式编程

    返回函数 匿名函数 装饰器 偏函数

  • Python 返回函数、匿名函数、装饰器、偏函数

    返回函数 匿名函数 装饰器 偏函数

  • 装饰器与偏函数

    装饰器的概念 在讲解装饰器之前,先看一段简单的程序,如下所示。 运行结果如下图所示。 运行结果如下图所示。 在上述...

  • chapter7 函数式编程

    闭包 匿名函数 装饰器 偏函数

  • Python - 学习理解带参数的装饰器

    理解带参数的装饰器 参考文章 Python精进-装饰器与函数对象 加了装饰器这段代码从一个函数定义(不会执行任何东...

  • python装饰器

    装饰器简述 要理解装饰器需要知道Python高阶函数和python闭包,Python高阶函数可以接受函数作为参数,...

网友评论

    本文标题:Python干货-装饰器与偏函数

    本文链接:https://www.haomeiwen.com/subject/ybbgtqtx.html