概述
写在前面: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 小结
我所用到的函数装饰器的场景:
-
优化递归函数:跟书中介绍的例子相同,斐波那契数列有一种解法便称之为“备忘录”,就是将已经计算出的结果保存在数组中,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 | 函数装饰器、迭代器和生成器所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复