• 函数装饰器和闭包(四)


    上一章:函数装饰器和闭包(三)

    单分派函数

    假设我们现在要开发一个函数,这个函数可以传入一个元素,函数要判断元素的类型,再将其打印出来

    from collections.abc import MutableSequence, MutableMapping
    
    
    def print_item(item):
        if isinstance(item, int):
            print("int:", item)
        elif isinstance(item, MutableSequence):
            print("iter:", item)
        elif isinstance(item, MutableMapping):
            print("map:", item)
        else:
            print(item)
    

      

    运行结果:

    >>> print_item(1)
    int: 1
    >>> print_item([1, 2, 3])
    sequence: [1, 2, 3]
    >>> print_item({"a": 1, "b": 2})
    map: {'a': 1, 'b': 2}
    

      

    这个函数很好理解,没有什么好解释的,但是我们要通过这个函数来展示如何使用functools.singledispatch装饰器让Python实现“重载”的效果

    from collections.abc import MutableSequence, MutableMapping
    from functools import singledispatch
    
    
    @singledispatch  # <1>
    def print_item(item):
        print(item)
    
    
    @print_item.register(int)  # <2>
    @print_item.register(float)
    def _(item):
        print("number:", item)
    
    
    @print_item.register(str)  # <3>
    def _(item):
        print("str:", item)
    
    
    @print_item.register(MutableSequence)  # <4>
    def _(item):
        print("sequence:", item)
    
    
    @print_item.register(MutableMapping)  # <5>
    def _(item):
        print("map:", item)
    

         

    我们用@singledispatch装饰了print_item函数,把这个函数作为基函数,然后再用@print_item.register装饰其他函数,当我们调用print_item,会根据item的类型查找应该执行的函数

    1. @singledispatch标记处理object类型的基函数
    2. 当传入参数为int类型进入此方法,这个时候专门的函数名称已经无关紧要了,我们用_代替,同时可以用多个@print_item.register装饰同一个函数
    3. 当传入参数为str类型进入此方法
    4. 当传入参数为序列类型进入此方法
    5. 当传入参数为字典类型进入此方法

      

    运行结果:

    >>> print_item(1)
    number: 1
    >>> print_item(1.1)
    number: 1.1
    >>> print_item("hello")
    str: hello
    >>> print_item([1, 2, 3])
    sequence: [1, 2, 3]
    >>> print_item({"a": 1, "b": 2})
    map: {'a': 1, 'b': 2}
    

    参数化装饰器

    Python在解释装饰器时,把被装饰的函数当做第一个参数传递给装饰器函数,但怎么样才能让装饰器接收其他参数呢?答案是:创建一个装饰器工厂函数,把参数传给它,返回一个装饰器,然后再把它应用到要装饰的函数上。可能这样的解释听得云里雾里,没关系,我们来看下面一个例子

    registry = set()  # <1>
    
    
    def register(active=True):  # <2>
        def decorate(func):  # <3>
            print('running register(active=%s)->decorate(%s)' % (active, func))
            if active:  # <4>
                registry.add(func)
            else:
                registry.discard(func)  # <5>
    
            return func  # <6>
    
        return decorate  # <7>
    
    
    @register(active=False)  # <8>
    def f1():
        print('running f1()')
    
    
    @register()  # <9>
    def f2():
        print('running f2()')
    
    
    def f3():
        print('running f3()')
    

      

    1. 声明一个名为registry的集合对象
    2. register方法接收一个可选的关键字参数
    3. decorate这个内部函数才是真正的装饰器,注意它只有一个参数,而且接收的是函数
    4. 只有active的值为真,才将func注册到registry集合中
    5. 如果active的值不为真,则将func从registry集合删除
    6. decorate是装饰器,必须返回一个函数
    7. register是装饰器工厂函数,因此返回decorate
    8. @register工厂函数必须作为函数调用,并且传入所需的参数
    9. 即时不传入参数,register也必须作为函数调用

    我们导入这个文件:

    >>> from registration_param import *
    running register(active=False)->decorate(<function f1 at 0x00000072D8DA4620>)
    running register(active=True)->decorate(<function f2 at 0x00000072D8DA46A8>)
    >>> registry
    {<function f2 at 0x00000072D8DA46A8>}
    

      

    可以看到,当把register作为装饰器工厂函数,返回的decorate函数得到了执行,由于f1传入的active为False,所以f1没有注册到registry集合对象里面,只有f2被注册到集合对象,我们打印registry,可以看到,里面确实只有f2函数对象

  • 相关阅读:
    Java日志框架Slf4j+Log4j入门
    Pandas常用函数入门
    Noip2018 倒计时
    【缩点】洛谷P3387
    用Visio进行数据库建模、设计和实现
    SQL Server 教程
    MS TransactSQL 存储过程的解密算法
    泛型编程
    网络实现语音
    Visual C++ 例程下载
  • 原文地址:https://www.cnblogs.com/beiluowuzheng/p/9310005.html
Copyright © 2020-2023  润新知