• Python武器库开发-高级特性篇(七)


    高级特性篇(七)

    装饰器

    装饰器是给现有的模块增添新的小功能,可以对原函数进行功能扩展,而且还不需要修改原函数的内容,也不需要修改原函数的调用。这也称为元编程,因为程序的一部分试图在编译时修改程序的另一部分。Python中的所有内容都是对象。我们定义的名称只是绑定到这些对象的标识符。函数也不例外,它们也是对象(带有属性)。可以将各种不同的名称绑定到同一功能对象。

    def first(msg):
        print(msg)    
    
    first("Hello")
    
    second = first
    second("Hello")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    当你运行代码时,这两个函数first和second给出相同的输出。在此,名称first和second指代相同的功能对象:

    在这里插入图片描述

    现在情况是不是感觉变复杂了点,可以将函数作为参数传递给另一个函数。这种以其他函数为参数的函数也称为高阶函数。这是这种函数的一个实例。

    def inc(x):
        return x + 1
    
    def dec(x):
        return x - 1
    
    def operate(func, x):
        result = func(x)
        return result
    
    print(operate(inc,3))
    print(operate(dec,3))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    程序的输出结果如下:

    在这里插入图片描述

    函数和方法被称为可调用的,因为它们可以被调用。

    实际上,任何实现特殊方法__call __()的对象都称为可调用的。 因此,从最基本的意义上讲,装饰器是可调用的,可返回可调用的。

    基本上,装饰器接受一个函数,添加一些功能并返回它。

    def make_pretty(func):
        def inner():
            print("我被装饰了")
            func()
        return inner
    
    def ordinary():
        print("我是普通的函数")
    
    print(ordinary())
    print("-----------------------")
    
    pretty = make_pretty(ordinary)
    print(pretty())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    程序的输出结果如下:

    在这里插入图片描述

    在上面显示的示例中,make_pretty()是一个装饰器,pretty = make_pretty(ordinary),函数ordinary()被修饰,返回的函数被命名为pretty。这是一个常见的构造,因此,Python具有简化此语法的语法。我们可以将@符号与装饰器函数的名称一起使用,并将其放置在要装饰的函数的定义上方。例如:

    def make_pretty(func):
        def inner():
            print("我被装饰了")
            func()
        return inner
    
    @make_pretty
    def ordinary():
        print("我是普通的函数")
    
    print(ordinary())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    就相当于

    def make_pretty(func):
        def inner():
            print("我被装饰了")
            func()
        return inner
    
    def ordinary():
        print("我是普通的函数")
    
    ordinary = make_pretty(ordinary)
    
    print(ordinary())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在Python中,我们可以通过完成的function(*args, **kwargs)。这样,args是位置参数的元组,kwargs而是关键字参数的字典。这样的装饰器的一个实例是:

    def works_for_all(func):
        def inner(*args, **kwargs):
            print("我可以装饰任何函数")
            return func(*args, **kwargs)
        return inner
    
    @works_for_all
    def test():
        print("我被装饰了")
    
    
    test()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    程序的输出结果如下:

    在这里插入图片描述

    在Python中,我们还可以链接多个装饰器。一个函数可以用不同(或相同)的装饰器多次装饰。我们只需将装饰器放置在所需函数之上。

    def star(func):
        def inner(*args, **kwargs):
            print("*" * 30)
            func(*args, **kwargs)
            print("*" * 30)
        return inner
    
    def percent(func):
        def inner(*args, **kwargs):
            print("%" * 30)
            func(*args, **kwargs)
            print("%" * 30)
        return inner
    
    @star
    @percent
    def printer(msg):
        print(msg)
    printer("Hello")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    程序的输出结果如下:

    在这里插入图片描述

    链接装饰器的顺序很重要。如果我们按相反的顺序

    def star(func):
        def inner(*args, **kwargs):
            print("*" * 30)
            func(*args, **kwargs)
            print("*" * 30)
        return inner
    
    def percent(func):
        def inner(*args, **kwargs):
            print("%" * 30)
            func(*args, **kwargs)
            print("%" * 30)
        return inner
    
    @percent
    @star
    def printer(msg):
        print(msg)
    printer("Hello")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    执行的程序结果输出将如下:

    在这里插入图片描述

    迭代器

    对于Python中的任意对象,只要它定义了可以返回一个迭代器的 _ iter_ 方法,或者定义了可以支持下标索引的 _ getitem_ 方法,那么它就是一个可迭代对象。对可迭代对象使用 _ iter_ 方法后,会返回一个迭代器。iter()函数(也就是__iter__()方法)从它们返回一个迭代器。我们使用该next()函数手动遍历迭代器的所有项目。 当我们到达末尾并且没有更多数据要返回时,它将引发StopIteration。 以下是一个示例:

    # 定义一个列表
    my_list = [4, 7, 0, 3]
    
    # 使用iter()获得迭代器
    my_iter = iter(my_list)
    
    ## 使用iter()获得迭代器 
    
    #输出 4
    print(next(my_iter))
    
    #输出 7
    print(next(my_iter))
    
    ## next(obj)与obj .__ next __()相同
    
    #输出 0
    print(my_iter.__next__())
    
    #输出 3
    print(my_iter.__next__())
    
    ## 这将引起错误,没有项目剩下
    next(my_iter)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    以上实例输出的结果如下:

    在这里插入图片描述

    在Python中从头开始构建迭代器很容易。我们只需要实现这些方法__iter__()和__next__()。iter()方法返回迭代器对象本身。如果需要,可以执行一些初始化。next()方法必须返回序列中的下一项。在到达终点时,以及在随后的调用中,它必须引发StopIteration。这里,我们展示了一个示例,它将在每次迭代中为我们提供2的次幂。幂指数从0到用户设置的数字:

    class PowTwo:
        """实现迭代器的类
                 二的幂"""
    
        def __init__(self, max = 0):
            self.max = max
    
        def __iter__(self):
            self.n = 0
            return self
    
        def __next__(self):
            if self.n <= self.max:
                result = 2 ** self.n
                self.n += 1
                return result
            else:
                raise StopIteration
    
    a = PowTwo(4)
    i = iter(a)
    
    print(next(i))
    print(next(i))
    print(next(i))
    print(next(i))
    print(next(i))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    以上实例输出的结果如下:

    在这里插入图片描述

    迭代器对象中的项不必耗尽。可能有无限的迭代器(永远不会结束)。在处理这样的迭代器时,我们必须小心。在这些类型的无限迭代器上进行迭代时,请小心包含终止条件。这是一个演示无限迭代器的简单示例:

    class InfIter:
        """无限迭代器返回所有
                     奇数"""
    
        def __iter__(self):
            self.num = 1
            return self
    
        def __next__(self):
            num = self.num
            self.num += 2
            return num
    
    a = iter(InfIter())
    
    print(next(a))
    print(next(a))
    print(next(a))
    print(next(a))
    print(next(a))
    print(next(a))
    print(next(a))
    print(next(a))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    运行结果如下:

    在这里插入图片描述

    生成器

    用Python构建迭代器有很多开销; 我们必须使用__iter__()和__next__()方法实现一个类,跟踪内部状态,在没有要返回的值时触发StopIteration等等。这既冗长又违反直觉。生成器在这种情况下可以派上用场。Python生成器是创建迭代器的简单方法。我们上面提到的所有开销都由Python的生成器自动处理。

    简而言之,生成器是一个函数,它返回一个对象(迭代器),我们可以对其进行迭代(一次一个值)。

    生成器是动态生成的,当你要迭代的对象有非常多的元素时,使用生成器能为你节约很多内存

    在Python中创建生成器非常简单。 就像使用yield语句而不是return语句定义普通函数一样容易。

    如果一个函数包含至少一个yield语句(它可能包含其他yield或return语句),那么它就成为一个生成器函数。yield和return都将从函数返回一些值。

    不同之处在于,当return语句完全终止一个函数时,yield语句会暂停该函数保存其所有状态,然后在后续调用时继续执行。

    这是生成器函数与常规函数的不同之处:

    • 生成器函数包含一个或多个yield语句。

    • 调用时,它返回一个对象(迭代器),但不会立即开始执行。

    • 像__iter__()和__next__()这样的方法会自动实现。因此,我们可以使用next()来遍历项目。

    • 一旦函数产生了结果,函数就会暂停,控制就会转移给调用者。

    • 局部变量及其状态在连续调用之间被记住。

    • 最后,当函数终止时,在进一步调用时会自动引发StopIteration。

    这是一个示例,用于说明上述所有要点。我们有一个my_gen()由几个yield语句命名的生成器函数:

    # 一个简单的生成器函数
    def my_gen():
        n = 1
        print('这是第一次打印')
        # 生成器函数包含yield语句
        yield n
    
        n += 1
        print('这是第二次打印')
        yield n
    
        n += 1
        print('这是最后一次打印')
        yield n
    
    # 它返回一个对象,但不立即开始执行
    a = my_gen()
    # 我们可以使用next()遍历这些项.
    next(a)
    # 一旦函数产生了结果,函数就会暂停,控制就会转移给调用者。
    
    # 局部变量及其状态在连续调用之间被记住。
    next(a)
    
    next(a)
    
    # 最后,当函数终止时,在进一步调用时将自动引发StopIteration。
    
    next(a)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    这是以上实列的输出结果:

    在这里插入图片描述我们可以直接将生成器与for循环一起使用。

    这是因为,for循环接受一个迭代器,并使用next()函数对其进行迭代。当StopIteration被触发时,它会自动结束

    # 一个简单的生成器函数
    def my_gen():
        n = 1
        print('这是第一次打印')
        # 生成器函数包含yield语句
        yield n
    
        n += 1
        print('这是第二次打印')
        yield n
    
        n += 1
        print('这是最后一次打印')
        yield n
    
    # 使用for循环
    for item in my_gen():
        print(item)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    运行该程序时,输出为:

    在这里插入图片描述

  • 相关阅读:
    2023年第九届数维杯国际大学生数学建模挑战赛A题
    Shell之练习一
    金融行业分布式数据库选型及实践经验
    vue3实现塔罗牌翻牌
    NOR Flash 和 NAND Flash 闪存详解
    文件管理命令 ls,别名
    npm 源切换:一条命令搞定
    英语语法基础--思维导图
    洛谷P8669 乘积最大
    git学习笔记
  • 原文地址:https://blog.csdn.net/qq_64973687/article/details/134054625