跳转到内容

Python 编程/技巧和窍门

来自维基教科书,开放世界中的开放书籍


在 Python 中,您可以学习许多技巧和窍门

字符串

[编辑 | 编辑源代码]
  • 三重引号是一种定义包含单引号和双引号的字符串的简单方法。
  • 字符串连接很昂贵。使用百分比格式化和 str.join() 进行连接

(但除非您的结果字符串超过 500-1000 个字符,否则不必担心) [1]

print "Spam" + " eggs" + " and" + " spam"               # DON'T DO THIS
print " ".join(["Spam","eggs","and","spam"])            # Much faster/more
                                                        # common Python idiom
print "%s %s %s %s" % ("Spam", "eggs", "and", "spam")   # Also a pythonic way of
                                                        # doing it - very fast

优化的 C 模块

[编辑 | 编辑源代码]

一些模块有使用 C 编写的优化版本,它们提供几乎相同的接口,并且通常比纯 Python 实现或更节省内存。模块行为通常在某些方面有所不同,通常是轻微的,因此 C 版本经常被使用。

这主要是 Python 2.x 的一个特性,它在 Python 3 中基本被移除,模块在可用时会自动使用优化实现。[2] 但是,cProfile/profile 对仍然存在(截至 Python 3.4)。

名为 moduleModule 的模块的 C 版本称为 cModule,并且经常使用 import...as 导入以去掉前缀,例如

import cPickle as pickle

为了兼容性,可以尝试导入 C 版本,如果 C 版本不可用则回退到 Python 版本;在这种情况下,使用 import...as必需的,因此代码不依赖于导入的模块

try:
  import cPickle as pickle
except ImportError:
  import pickle

值得注意的例子包括

  • (Python 2.x) cPickle 用于 pickle,快 1000 倍。
  • (Python 2.x) cStringIO 用于 StringIO,在 Python 3 中被 io.StringIO 替换
  • cProfile 用于 profile - Python profile 会增加显著的开销,因此 cProfile 对于大多数用途来说是推荐的。
  • (在 Python 3.3+ 中不需要) cElementTree 用于 ElementTree,速度快 15-20 倍,并且使用 2-5 倍更少的内存;[3] 在 Python 3.3+ 中不需要,因为它会在可能的情况下自动使用快速实现。

列表推导和生成器

[编辑 | 编辑源代码]
  • 列表推导和生成器表达式对于处理小型、紧凑的循环非常有用。此外,它比普通的 for 循环更快。
directory = os.listdir(os.getcwd())       # Gets a list of files in the
                                          # directory the program runs from
filesInDir = [item for item in directory] # Normal For Loop rules apply, you
                                          # can add "if condition" to make a
                                          # more narrow search.
  • 列表推导和生成器表达式可以与 zip 或 itertools.izip 一起使用来处理两个(或多个)列表。
[a - b for (a,b) in zip((1,2,3), (1,2,3))]  # will return [0, 0, 0]

数据类型选择

[编辑 | 编辑源代码]

选择正确的数据类型对于应用程序的性能至关重要。例如,假设您有两个列表

list1 = [{'a': 1, 'b': 2}, {'c': 3, 'd': 4}, {'e': 5, 'f': 6}]
list2 = [{'e': 5, 'f': 6}, {'g': 7, 'h': 8}, {'i': 9, 'j': 10}]

并且您想找到两个列表中都存在的条目。您可以遍历一个列表,检查另一个列表中是否有公共项目

common = []
for entry in list1:
    if entry in list2:
        common.append(entry)

对于这样的短列表,这会很好用,但是对于较长的列表,例如每个列表包含数千个条目时,以下方法会更高效,并且会产生相同的结果

set1 = set([tuple(entry.items()) for entry in list1])
set2 = set([tuple(entry.items()) for entry in list2])
common = set1.intersection(set2)
common = [dict(entry) for entry in common]

集合在这样的函数中针对速度进行了优化。字典本身不能作为集合的成员使用,因为它们是可变的,但元组可以。如果需要对字典列表执行集合操作,可以将项目转换为元组,将列表转换为集合,执行操作,然后转换回来。这通常比尝试使用字符串函数来复制集合操作要快得多。

  • 装饰器可用于处理常见的注意事项,例如日志记录、数据库访问等。
  • 虽然 Python 没有内置函数来展平列表,但您可以使用递归函数快速完成这项工作。
def flatten(seq, list = None):
    """flatten(seq, list = None) -> list

    Return a flat version of the iterator `seq` appended to `list`
    """
    if list == None:
        list = []
    try:                          # Can `seq` be iterated over?
        for item in seq:          # If so then iterate over `seq`
            flatten(item, list)      # and make the same check on each item.
    except TypeError:             # If seq isn't iterable
        list.append(seq)             # append it to the new list.
    return list
  • 要阻止 Python 脚本在独立启动后立即关闭,请添加以下代码
print 'Hit Enter to exit'
raw_input()
  • Python 本身就有一个 GUI:Tkinter,基于 Tcl 的 Tk。还有更多可用,例如 PyQt4、pygtk3 和 wxPython。
  • 三元运算符
[on_true] if [expression] else [on_false]

x, y = 50, 25

small = x if x < y else y
  • 布尔值作为索引
b = 1==1
name = "I am %s" % ["John","Doe"][b]
#returns I am Doe

参考文献

[编辑 | 编辑源代码]
  1. "'concat vs join - followup' on 'Python Rocks! and other rants 27.8.2004 Weblog of Kent S Johnson'". August 27, 2004. Retrieved 2008-08-29.
  2. Python 3.0 中的新内容, Guido van Rossum
  3. "cElementTree 模块", January 30, 2005, Fredrik Lundh
华夏公益教科书