我是靠谱客的博主 优美季节,最近开发中收集的这篇文章主要介绍Fluent Python | 函数装饰器、迭代器和生成器,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

写在前面:Fluent Python 系列是学习《Fluent Python》的笔记 ~ 这是一本适合Python进阶的书,不仅有一些高级语法,作者对部分底层实现也有讲解,以便于我们理解Python的设计,比如为什么普通字典是无序的呢?

更新记录
2021.10.12 函数装饰器(最初的需求:实现类似其他面向对象语言的函数重载)
2021.11.10 迭代器和生成器(同学问我的面试题:python3中range和python 2中xrange的区别)

目录

      • 函数装饰器
        • 1 变量作用域
        • 2 闭包
        • 3 装饰器
          • 3.1 基本概念和写法
          • 3.2 装饰器何时执行
          • 3.3 标准库中常用的两个装饰器函数
          • 3.4 参数化装饰器
        • 4 小结
      • 迭代器和生成器
        • 1 序列可迭代
        • 2 可迭代对象和迭代器
        • 3 生成器
          • 3.1 什么是生成器
          • 3.2 生成器函数
          • 3.3 生成器表达式
          • 3.4 标准库中常用的生成器函数
        • 4 小结

函数装饰器

1 变量作用域

注意函数体内赋值的局部变量与函数体外同名全局变量


 

 

2 闭包


 

 

3 装饰器

3.1 基本概念和写法

 
import time
from clockedeco import clock
from functools import lru_cache


@clock
def snooze(seconds):
    time.sleep(seconds)

    
    
#@clock    
#def factorial(n):
#    return 1 if n < 2 else factorial(n-1)

def factorial(n):
    return 1 if n < 2 else factorial(n-1)
factorial = clock(factorial)

@lru_cache()
@clock
def fibonacci(n):
    if n < 2 :
        return n
    else:
        return fibonacci(n-2) + fibonacci(n-1)

if __name__ == '__main__':
#    print('*' * 40, 'Calling snooze(.123)')
#    snooze(.123)                                # 此时调用的已经是被装饰过的函数
#    print('*' * 40, 'Calling factorial(6)')
#    print('6!=', factorial(6))
    print(fibonacci(6))

 

3.2 装饰器何时执行

 
registry = []

# 定义装饰器
def register(func):
    print('running register(%s)' % func)
    registry.append(func)
    return func

# 定义被装饰的函数
@register
def f1():
    print('running f1()')

def f3():
    print('runing f3()')

def main():
    print('running main()')
    print('registry->', registry)
    f1()    # 调用被装饰的函数
    f3()

if __name__ == '__main__':
    main()

 

3.3 标准库中常用的两个装饰器函数

 
from functools import singledispatch
from collections import abc
import numbers
import html

@singledispatch
def htmlize(obj):
    """处理Object类型的基函数"""
    content = html.escape(repr(obj))
    return '<pre>{}</pre>'.format(content)

# 以下各个专门函数使用@《base_function》.register()装饰
@htmlize.register(str)
def _(text):    # 专门函数的名称无关紧要
    content = html.escape(text).replace('n', '<br>n')
    return '<p>{0}</p>'.format(content)

@htmlize.register(numbers.Integral)
def _(n):
    return '<pre>{0} (0x{0:x})</pre>'.format(n)
    
@htmlize.register(tuple)
@htmlize.register(abc.MutableSequence)
def _(seq):
    inner = '</li>n<li>'.join(htmlize(item) for item in seq)
    return '<ul>n<li>' + inner + '</li>n</ul>'

 

3.4 参数化装饰器

 

4 小结

我所用到的函数装饰器的场景:

  1. 优化递归函数:跟书中介绍的例子相同,斐波那契数列有一种解法便称之为“备忘录”,就是将已经计算出的结果保存在数组中,eg:保存f(1), f(2),这样在计算f(3)=f(1)+f(2)的时候就不需要再重复计算f(1)和f(2),只需要在数组中查找即可。Python内嵌的装饰器实现了备忘录的功能,不需要手动再设置数组保存结果,直接使用@lru_cache装饰器即可。

    https://leetcode-cn.com/problems/fibonacci-number/

2.使用Python实现类似C++/Java 函数重载的功能
Python确实没有函数重载,遇到针对不同情况调用不同函数的时候,最简单的方法就是使用if-elif-else分别调用专门的函数,这种做法的扩展性确实不好。

 


迭代器和生成器

小插曲:同学面试腾讯,面试官的一个问题是:Python3的range()和Python2的xrange()区别是什么?然后我第一次认真审视了“迭代器和生成器”这两个概念hhh,之后在自己的程序中也多次用到,今天系统回顾一下这部分的内容。

1 序列可迭代

在Python中,所有的集合都是可以迭代的,迭代器用于支持:

  • for循环
  • 构建和扩展集合类型
  • 逐行遍历文本文件
  • 列表推导、字典推导、集合推导
  • 元组拆包
  • 函数调用时,使用*拆包参数

 

 

2 可迭代对象和迭代器


 

Example 1:Sentence类用于生成可迭代对象;SentenceIterator类用于生成迭代器对象。

import re                   # 使Python具有正则表达式功能
import reprlib

RE_WORD = re.compile('w+') # 用于匹配一个或者多个 字母、数字、下划线
class Sentence:
    def __init__(self, text):
        self.text = text
        self.words = RE_WORD.findall(text)  # 返回正则表达式非重叠匹配的字符串列表
         
    def __repr__(self):
        return 'Sentence(%s)' % reprlib.repr(self.text) # 生成简略字符串表示形式
    
    def __iter__(self):
        return SentenceIterator(self.words) # 实例化并返回迭代器



class SentenceIterator:
    def __init__(self, words):
        self.words = words
        self.index = 0
    
    def __next__(self):
        try:
            word = self.words[self.index]
        except IndexError:
            raise StopIteration()
        self.index += 1
        return word
    
    def __iter__(self):
        return self                         # 返回迭代器对象本身

 
Example 2:更加符合Python风格的写法,使用生成器函数。

import re                   # 使Python具有正则表达式功能
import reprlib

RE_WORD = re.compile('w+') # 用于匹配一个或者多个 字母、数字、下划线
class Sentence:
    def __init__(self, text):
        self.text = text
        self.words = RE_WORD.findall(text)  # 返回正则表达式非重叠匹配的字符串列表
         
    def __repr__(self):
        return 'Sentence(%s)' % reprlib.repr(self.text) # 生成简略字符串表示形式
    
    def __iter__(self):     # 使用了yield关键字-->生成器函数
        for word in self.words:
            yield word
        return

 

3 生成器

3.1 什么是生成器

 
3.2 生成器函数

 
# 生成器函数
def gen_AB():
    print('start')
    yield 'A'
    print('continue')
    yield 'B'
    print('end')

for c in gen_AB():
    print('-->', c)

 

3.3 生成器表达式

 
# 生成器表达式和列表推导
# 列表推导-->迫切迭代gen_AB()生成的生成器对象产出的元素
res1 = [x*3 for x in gen_AB()]
print(res1)

# 生成器表达式-->生成器对象 这里gen_AB()并没有真正执行
res2 = (x*3 for x in gen_AB())
for i in res2:      # for 循环迭代隐式调用next(res2),gen_AB()才会真正执行
    print('-->', i)

 

3.4 标准库中常用的生成器函数

 

4 小结

1.迭代器和生成器其实在很多应用场景下被隐式的创建和调用,比如for循环中,以及上面提到的range();关于二者的关系,实际的应用环境中其实也不会严格的区分。


 

2.这部分的核心内容:Python是从可迭代对象中创建迭代器的,那什么是可迭代对象呢?我们认为实现了可以返回迭代器对象的__iter__()或者__getitem__()的对象为可迭代对象。进而__iter__()返回的迭代器对象又是什么样子的呢?要求迭代器对象必须实现__next__()和__iter__()这两个方法,分别用于返回下一个元素和对象本身。不过在Python中,经常使用生成器来完成迭代器对象的功能,而生成器对象是由生成器函数或者生成器表达式返回的,使用yiled关键字的函数就是生成器函数。

最后

以上就是优美季节为你收集整理的Fluent Python | 函数装饰器、迭代器和生成器的全部内容,希望文章能够帮你解决Fluent Python | 函数装饰器、迭代器和生成器所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(33)

评论列表共有 0 条评论

立即
投稿
返回
顶部