- 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章 性能剖析与优化
建议30:[]、() 和 {}:一致的容器初始化形式
列表是一个很有用的数据结构,它在Python中属于可变对象,列表中的元素没有限制,可以重复可以嵌套,操作上支持对单个元素的读取和修改,还支持分片、排序、插入、删除等。由于其灵活性,在实际应用中经常会看到它的身影。下面的程序遍历列表中的每个元素,并根据要求(去掉单词所包含的空格后首字母是否为大写)生成一个新的list。
words = [' Are', ' abandon', 'Passion','Business',' fruit ','quit'] size = len(words) newlist = [] for i in range(size): if words[i].strip().istitle(): newlist.append(words[i] ) print newlist
那么,这段程序有什么问题吗?就程序本身来说并没有什么明显的问题,但有更好的实现方式。这就是列表解析(list comprehension)所涉及的内容了。先来了解一下列表解析的基本知识点。
列表解析的语法为:[expr for iter_item in iterable if cond_expr]。它迭代iterable 中的每一个元素,当条件满足的时候便根据表达式expr计算的内容生成一个元素并放入新的列表中,依次类推,并最终返回整个列表。在语法上,它等价于下面代码段:
Newlist = [] for iter_item in iterable: if cond_expr: Newlist.append(expr)
其中条件表达式不是必需的,如果没有条件表达式,就直接将expr中计算出的元素加入List中。列表解析的使用非常灵活。
1)支持多重嵌套。如果需要生成一个二维列表可以使用列表解析嵌套的方式。示例如下:
>>> nested_list = [['Hello', 'World'], ['Goodbye', 'World']] >>> nested_list = [[s.upper() for s in xs] for xs in nested_list] >>> print nested_list [['HELLO', 'WORLD'], ['GOODBYE', 'WORLD']] >>>
2)支持多重迭代。下面的例子中a、b分别对应两个列表中的元素,[(a,b) for a in ['a','1',1,2] for b in ['1',3,4,'b'] if a != b]表示:列表['a','1',1,2]和['1',3,4,'b']依次求笛卡儿积之后并去掉元素值相等的元组之后所剩下的元组的集合。
>>> [(a,b) for a in ['a','1',1,2] for b in ['1',3,4,'b'] if a != b] [('a', '1'), ('a', 3), ('a', 4), ('a', 'b'), ('1', 3), ('1', 4), ('1', 'b'), (1, '1'), (1, 3), (1, 4), (1, 'b'), (2, '1'), (2, 3), (2, 4), (2, 'b')] >>>
3)列表解析语法中的表达式可以是简单表达式,也可以是复杂表达式,甚至是函数。
>>> def f(v): ... if v%2 == 0: ... v = v**2 ... else: ... v = v+1 ... return v ... >>> [f(v) for v in [2,3,4,-1] if v>0] # 表达式可以是函数 [4, 4, 16] >>> [v**2 if v%2 ==0 else v+1 for v in [2,3,4,-1] if v>0]# 也可以是普通计算 [4, 4, 16] >>>
4)列表解析语法中的iterable可以是任意可迭代对象。下面的例子中把文件句柄当做一个可迭代对象,可轻易读出文件内容。
fh = open("test.txt", "r") result = [i for i in fh if "abc" in i] # 文件句柄可以当做可迭代对象 print result
了解完列表解析的基本知识之后,本节开头的例子你应该知道怎么使用更为简洁了。那么,为什么要推荐在需要生成列表的时候使用列表解析呢?
1)使用列表解析更为直观清晰,代码更为简洁。本节开头的例子改用列表解析,直接可将代码行数减少为2行,这在大型复杂应用程序中尤为重要,因为这意味着潜在的缺陷较小,同时代码清晰直观,更容易阅读和理解,可维护性更强。
2)列表解析的效率更高。本节开头的例子用两种不同方法实现后进行测试,测试结果表明列表解析在时间上有一定的优势,这主要是因为普通循环生成List的时候一般需要多次调用append()函数,增加了额外的时间开销。需要说明的是对于大数据处理,列表解析并不是一个最佳选择,过多的内存消耗可能会导致MemoryError。
除了列表可以使用列表解析的语法之外,其他几种内置的数据结构也支持,比如元组(tuple)的初始化语法是(expr for iter_item in iterable if cond_expr),而集合(set)的初始化语法是{expr for iter_item in iterable if cond_expr},甚至字典(dict)也有类似的语法{expr1, expr2 for iter_item in iterable if cond_expr}。它们的使用类似列表解析,但需要注意,因为元组也适用赋值语句的装箱和拆箱机制,所以需要注意(1)与(1,)是不同的:前者为数字1,后者才代表元组(注意1后面的“,”)。
>>> type((1)) <type 'int'> >>> type((1,)) <type 'tuple'> >>>
此外,当函数接受一个可迭代对象参数时,可以使用元组的简写方式。
>>> def foo(a): ... for i in a: ... print i ... >>> foo([1, 2, 3]) 1 2 3 >>> foo(i for i in range(3) if i % 2 == 0) 0 2
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论