- Preface 前言
- 第1章 引论
- 第2章 编程惯用法
- 第3章 基础语法
- 建议19:有节制地使用 from…import 语句
- 建议20:优先使用 absolute import 来导入模块
- 建议21:i+=1 不等于 ++i
- 建议22:使用 with 自动关闭资源
- 建议23:使用 else 子句简化循环(异常处理)
- 建议24:遵循异常处理的几点基本原则
- 建议25:避免 finally 中可能发生的陷阱
- 建议26:深入理解 None 正确判断对象是否为空
- 建议27:连接字符串应优先使用 join 而不是 +
- 建议28:格式化字符串时尽量使用 .format 方式而不是 %
- 建议29:区别对待可变对象和不可变对象
- 建议30:[]、() 和 {}:一致的容器初始化形式
- 建议31:记住函数传参既不是传值也不是传引用
- 建议32:警惕默认参数潜在的问题
- 建议33:慎用变长参数
- 建议34:深入理解 str() 和 repr() 的区别
- 建议35:分清 staticmethod 和 classmethod 的适用场景
- 第4章 库
- 建议36:掌握字符串的基本用法
- 建议37:按需选择 sort() 或者 sorted()
- 建议38:使用 copy 模块深拷贝对象
- 建议39:使用 Counter 进行计数统计
- 建议40:深入掌握 ConfigParser
- 建议41:使用 argparse 处理命令行参数
- 建议42:使用 pandas 处理大型 CSV 文件
- 建议43:一般情况使用 ElementTree 解析 XML
- 建议44:理解模块 pickle 优劣
- 建议45:序列化的另一个不错的选择 JSON
- 建议46:使用 traceback 获取栈信息
- 建议47:使用 logging 记录日志信息
- 建议48:使用 threading 模块编写多线程程序
- 建议49:使用 Queue 使多线程编程更安全
- 第5章 设计模式
- 第6章 内部机制
- 建议54:理解 built-in objects
- 建议55:init() 不是构造方法
- 建议56:理解名字查找机制
- 建议57:为什么需要 self 参数
- 建议58:理解 MRO 与多继承
- 建议59:理解描述符机制
- 建议60:区别 getattr() 和 getattribute() 方法
- 建议61:使用更为安全的 property
- 建议62:掌握 metaclass
- 建议63:熟悉 Python 对象协议
- 建议64:利用操作符重载实现中缀语法
- 建议65:熟悉 Python 的迭代器协议
- 建议66:熟悉 Python 的生成器
- 建议67:基于生成器的协程及 greenlet
- 建议68:理解 GIL 的局限性
- 建议69:对象的管理与垃圾回收
- 第7章 使用工具辅助项目开发
- 第8章 性能剖析与优化
建议64:利用操作符重载实现中缀语法
可能你跟我一样,学完各种对象协议后就跃跃欲试。当年我初学Python的时候,原本最熟悉的编程语言是C++,所以学会操作符重载以后,就拿来炫技了。
>>> class endl(object):pass ... >>> class Cout(object): ... def __lshift__(self, obj): ... if obj is endl: ... print ... return ... print obj, ... return self ... >>> cout = Cout() >>> cout << 1 << 2 << endl 1 2
如果你像我当年那样初学Python,你就会明白这种模拟C++的流输出让我感觉有多炫!但是现在我知道这是一种对特性的滥用,不应提倡。不过我在这里重提旧事的原因是想要引出一个非常棒的利用操作符重载实现更优雅的代码的例子。
熟悉Shell脚本编程朋友应该都非常熟悉“|”这个符号,它表示管道,用以连接两个应用程序的输入输出。比如按字母表反序遍历当前目录的文件与子目录,可以如下使用:
$ ls | sort -r test releases prj intern doc common branches art
管道的处理非常清晰,因为它是中缀语法。而我们常用的Python是前缀语法的,比如类似的Python代码应该是sort(ls(),reverse=True),明显没有那么清晰,特别是在极限情况下。
sum(select(where(take_while(fib(), lambda x: x < 1000000) lambda x: x % 2), lambda x: x * x))
像这样的代码,一堆sum、select、where混在一起,一眼看过去已经头大如斗了。管道符号在Python中,也是或符号,那么有没有可能利用它来简化代码呢?这个想法后来由Julien Palard开发了一个pipe库,达成了所愿。这个pipe库的核心代码只有几行,就是重载了__ror__()方法。
class Pipe: def __init__(self, function): self.function = function def __ror__(self, other): return self.function(other) def __call__(self, *args, **kwargs): return Pipe(lambda x: self.function(x, *args, **kwargs))
这个Pipe类可以当成函数的decorator来使用。比如在列表中筛选数据,可使用如下实现:
@Pipe def where(iterable, predicate): return (x for x in iterable if (predicate(x)))
pipe库内置了一堆这样的处理函数,上文所述的sum、select、where等函数尽在其中,所以马上就可以拿来改造之前的代码。
fib() | take_while(lambda x: x < 1000000) \ | where(lambda x: x % 2) \ | select(lambda x: x * x) \ | sum()
看,现在是不是一眼就可以看出代码的意义了呢?就是找出小于1000000的斐波那契数,并计算其中的偶数的平方之和。通过这个例子,可以看出中缀语法在这种流式数据处理上的确是非常有优势的。
pipe已经发布到pypi,可以使用pip install pip命令安装。安装完成以后可以在Python Shell中尝试一下。
>>> from pipe import * >>> [1, 2, 3, 4, 5] | where(lambda x: x % 2) | tail(2) | select(lambda x: x * x) | add 34
此外,pipe是惰性求值的,所以我们完全可以弄一个无穷生成器而不用担心内存被用完。比如:
>>> def fib(): ... a, b = 0, 1 ... while True: ... yield a ... a, b = b, a + b
然后来做一个题目:计算小于4?000?000的斐波那契数中的偶数之和。
>>> euler2 = fib() | where(lambda x: x % 2 == 0) | take_while(lambda x: x < 4000000) | add >>> assert euler2 == 4613732
可以看到代码非常易读,就像读自然语言一样。除了处理数值很方便,用它来处理文本也一样简单。看看这个需求:读取文件,统计文件中每个单词出现的次数,然后按照次数从高到低对单词排序。
from __future__ import print_function from re import split from pipe import * with open('test_descriptor.py') as f: print(f.read() | Pipe(lambda x:split('/W+', x)) | Pipe(lambda x:(i for i in x if i.strip())) | groupby(lambda x:x) | select(lambda x:(x[0], (x[1] | count))) | sort(key=lambda x:x[1], reverse=True) )
看看,非常简单吧?在我这里运行的结果如下:
[('self', 13), ('foo', 9), ('item', 9), ('_data', 8), ('print', 7), ('def', 5), ('return', 5), ('Jeff', 4), ('i', 4), ('in', 4), ('jeff', 4), ('ken', 4), ('obj', 4), ('val', 4), ('class', 3), ('lai', 3), ('pan', 3), ('tmp', 3), ('Foo', 2), ('ItemDescriptor', 2), ('Wrapper', 2), ('__iter__', 2), ('for', 2), ('if', 2), ('next', 2), ('object', 2), ('0', 1), ('1', 1), ('30', 1), ('8', 1), ('None', 1), ('__class__', 1), ('__future__', 1), ('__get__', 1), ('__init__', 1), ('__set__', 1), ('bin', 1), ('coding', 1), ('env', 1), ('f', 1), ('from', 1), ('import', 1), ('instance', 1), ('isinstance', 1), ('len', 1), ('list', 1), ('print_function', 1), ('python', 1), ('type', 1), ('usr', 1), ('utf', 1)]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论