admin 管理员组

文章数量: 1184232


2024年4月25日发(作者:c++全局变量和局部变量)

Docs » 10. Python 标准库概览

10. Python 标准库概览

10.1. 操作系统接口

os 模块提供了很多与操作系统交互的函数:

>>> import os

>>> () # Return the current working directory

'C:Python35'

>>> ('/server/accesslogs') # Change current working directory

>>> ('mkdir today') # Run the command mkdir in the system shell

0

应该用

import os

风格而非

from os import *

。这样可以保证随操作系统不同而有所变

化的 () 不会覆盖内置函数 open()。

在使用一些像 os 这样的大型模块时内置的 dir() 和 help() 函数非常有用:

>>> import os

>>> dir(os)

>>> help(os)

针对日常的文件和目录管理任务,shutil 模块提供了一个易于使用的高级接口:

>>> import shutil

>>> le('', '')

''

>>> ('/build/executables', 'installdir')

'installdir'

10.2. 文件通配符

glob 模块提供了一个函数用于从目录通配符搜索中生成文件列表:

>>> import glob

>>> ('*.py')

['', '', '']

10.3. 命令行参数

通用工具脚本经常调用命令行参数。这些命令行参数以链表形式存储于 sys 模块的 argv

变量。例如在命令行中执行

python one two three

后可以得到以下输出结果:

>>> import sys

>>> print()

['', 'one', 'two', 'three']

getopt 模块使用 Unix getopt() 函数处理 。更多的复杂命令行处理由 argparse 模

块提供。

10.4. 错误输出重定向和程序终止

sys 还有 stdin, stdout 和 stderr 属性,即使在 stdout 被重定向时,后者也可以用于显示

警告和错误信息:

>>> ('Warning, log file not found starting a new onen')

Warning, log file not found starting a new one

大多脚本的直接终止都使用

()

10.5. 字符串正则匹配

re 模块为高级字符串处理提供了正则表达式工具。对于复杂的匹配和处理,正则表达

式提供了简洁、优化的解决方案:

>>> import re

>>> l(r'bf[a‐z]*', 'which foot or hand fell fastest')

['foot', 'fell', 'fastest']

>>> (r'(b[a‐z]+) 1', r'1', 'cat in the the hat')

'cat in the hat'

只需简单的操作时,字符串方法最好用,因为它们易读,又容易调试:

>>> 'tea for too'.replace('too', 'two')

'tea for two'

10.6. 数学

math 模块为浮点运算提供了对底层C函数库的访问:

>>> import math

>>> ( / 4.0)

0.74757

>>> (1024, 2)

10.0

random 提供了生成随机数的工具:

>>> import random

>>> (['apple', 'pear', 'banana'])

'apple'

>>> (range(100), 10) # sampling without replacement

[30, 83, 16, 4, 8, 81, 41, 50, 18, 33]

>>> () # random float

0.17976

>>> nge(6) # random integer chosen from range(6)

4

SciPy <> 项目提供了许多数值计算的模块。

10.7. 互联网访问

有几个模块用于访问互联网以及处理网络通信协议。其中最简单的两个是用于处理从

urls 接收的数据的 t 以及用于发送电子邮件的 smtplib:

>>> from t import urlopen

>>> for line in urlopen('/cgi‐bin/'):

... line = ('utf‐8') # Decoding the binary data to text.

... if 'EST' in line or 'EDT' in line: # look for Eastern Time

... print(line)


Nov. 25, 09:43:32 PM EST

>>> import smtplib

>>> server = ('localhost')

>>> il('soothsayer@', 'jcaesar@',

... """To: jcaesar@

... From: soothsayer@

...

... Beware the Ides of March.

... """)

>>> ()

(注意第二个例子需要在 localhost 运行一个邮件服务器。)

10.8. 日期和时间

datetime 模块为日期和时间处理同时提供了简单和复杂的方法。支持日期和时间算法

的同时,实现的重点放在更有效的处理和格式化输出。该模块还支持时区处理。

>>> # dates are easily constructed and formatted

>>> from datetime import date

>>> now = ()

>>> now

(2003, 12, 2)

>>> me("%m‐%d‐%y. %d %b %Y is a %A on the %d day of %B.")

'12‐02‐03. 02 Dec 2003 is a Tuesday on the 02 day of December.'

>>> # dates support calendar arithmetic

>>> birthday = date(1964, 7, 31)

>>> age = now ‐ birthday

>>>

14368

10.9. 数据压缩

以下模块直接支持通用的数据打包和压缩格式:zlib, gzip, bz2, lzma, zipfile 以及

tarfile。

>>> import zlib

>>> s = b'witch which has which witches wrist watch'

>>> len(s)

41

>>> t = ss(s)

>>> len(t)

37

>>> ress(t)

b'witch which has which witches wrist watch'

>>> 32(s)

226805979

10.10. 性能度量

有些用户对了解解决同一问题的不同方法之间的性能差异很感兴趣。Python 提供了一

个度量工具,为这些问题提供了直接答案。

例如,使用元组封装和拆封来交换元素看起来要比使用传统的方法要诱人的多。timeit

证明了后者更快一些:

>>> from timeit import Timer

>>> Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()

0.57535828626024577

>>> Timer('a,b = b,a', 'a=1; b=2').timeit()

0.54962537085770791

相对于 timeit 的细粒度,profile 和 pstats 模块提供了针对更大代码块的时间度量工

具。

10.11. 质量控制

开发高质量软件的方法之一是为每一个函数开发测试代码,并且在开发过程中经常进

行测试。

doctest 模块提供了一个工具,扫描模块并根据程序中内嵌的文档字符串执行测试。测

试构造如同简单的将它的输出结果剪切并粘贴到文档字符串中。通过用户提供的例

子,它发展了文档,允许 doctest 模块确认代码的结果是否与文档一致:

def average(values):

"""Computes the arithmetic mean of a list of numbers.

>>> print(average([20, 30, 70]))

40.0

"""

return sum(values) / len(values)

import doctest

d() # automatically validate the embedded tests

unittest 模块不像 doctest 模块那么容易使用,不过它可以在一个独立的文件里提供一

个更全面的测试集:

import unittest

class TestStatisticalFunctions(se):

def test_average(self):

Equal(average([20, 30, 70]), 40.0)

Equal(round(average([1, 5, 7]), 1), 4.3)

with Raises(ZeroDivisionError):

average([])

with Raises(TypeError):

average(20, 30, 70)

() # Calling from the command line invokes all tests

10.12. “瑞士军刀”

Python 展现了“瑞士军刀”的哲学。这可以通过它更大的包的高级和健壮的功能来得到

最好的展现。列如:

和 模块让远程过程调用变得轻而易举。尽管模块有这样

的名字,用户无需拥有 XML 的知识或处理 XML。

email 包是一个管理邮件信息的库,包括MIME和其它基于 RFC2822 的信息文档。

不同于实际发送和接收信息的 smtplib 和 poplib 模块,email 包包含一个构造或解析

复杂消息结构(包括附件)及实现互联网编码和头协议的完整工具集。

和 包为流行的信息交换格式提供了强大的支持。同样, csv 模块支

持在通用数据库格式中直接读写。

综合起来,这些模块和包大大简化了 Python 应用程序和其它工具之间的数据交

换。

国际化由 gettext, locale 和 codecs 包支持。

Docs » 11. 标准库浏览 – Part II

11. 标准库浏览 – Part II

第二部分包含了支持专业编程工作所需的更高级的模块,这些模块很少出现在小脚本

中。

11.1. 输出格式

reprlib 模块为大型的或深度嵌套的容器缩写显示提供了 :repr() 函数的一个定制版本:

>>> import reprlib

>>> (set('supercalifragilisticexpialidocious'))

"set(['a', 'c', 'd', 'e', 'f', 'g', ...])"

pprint 模块给老手提供了一种解释器可读的方式深入控制内置和用户自定义对象的打

印。当输出超过一行的时候,“美化打印(pretty printer)”添加断行和标识符,使得数

据结构显示的更清晰:

>>> import pprint

>>> t = [[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta',

... 'yellow'], 'blue']]]

...

>>> (t, width=30)

[[[['black', 'cyan'],

'white',

['green', 'red']],

[['magenta', 'yellow'],

'blue']]]

textwrap 模块格式化文本段落以适应设定的屏宽:

>>> import textwrap

>>> doc = """The wrap() method is just like fill() except that it returns

... a list of strings instead of one big string with newlines to separate

... the wrapped lines."""

...

>>> print((doc, width=40))

The wrap() method is just like fill()

except that it returns a list of strings

instead of one big string with newlines

to separate the wrapped lines.

locale 模块按访问预定好的国家信息数据库。locale 的格式化函数属性集提供了一个直

接方式以分组标示格式化数字:

>>> import locale

>>> ale(_ALL, 'English_United States.1252')

'English_United States.1252'

>>> conv = conv() # get a mapping of conventions

>>> x = 1234567.8

>>> ("%d", x, grouping=True)

'1,234,567'

>>> _string("%s%.*f", (conv['currency_symbol'],

... conv['frac_digits'], x), grouping=True)

'$1,234,567.80'

11.2. 模板

string 提供了一个灵活多变的模版类 Template ,使用它最终用户可以用简单的进行编

辑。这使用户可以在不进行改变的情况下定制他们的应用程序。

格式使用

$

为开头的 Python 合法标识(数字、字母和下划线)作为占位符。占位符

$$

外面的大括号使它可以和其它的字符不加空格混在一起。 创建一个单独的

$

:

>>> from string import Template

>>> t = Template('${village}folk send $$10 to $cause.')

>>> tute(village='Nottingham', cause='the ditch fund')

'Nottinghamfolk send $10 to the ditch fund.'

当一个占位符在字典或关键字参数中没有被提供时,substitute() 方法就会抛出一个

KeyError 异常。 对于邮件合并风格的应用程序,用户提供的数据可能并不完整,这时

使用 safe_substitute() 方法可能更适合 — 如果数据不完整,它就不会改变占位符:

>>> t = Template('Return the $item to $owner.')

>>> d = dict(item='unladen swallow')

>>> tute(d)

Traceback (most recent call last):

...

KeyError: 'owner'

>>> _substitute(d)

'Return the unladen swallow to $owner.'

模板子类可以指定一个自定义分隔符。例如,图像查看器的批量重命名工具可能选择

使用百分号作为占位符,像当前日期,图片序列号或文件格式:

>>> import time,

>>> photofiles = ['img_', 'img_', 'img_']

>>> class BatchRename(Template):

... delimiter = '%'

>>> fmt = input('Enter rename style (%d‐date %n‐seqnum %f‐format): ')

Enter rename style (%d‐date %n‐seqnum %f‐format): Ashley_%n%f

>>> t = BatchRename(fmt)

>>> date = me('%d%b%y')

>>> for i, filename in enumerate(photofiles):

... base, ext = xt(filename)

... newname = tute(d=date, n=i, f=ext)

... print('{0} ‐‐> {1}'.format(filename, newname))

img_ ‐‐> Ashley_

img_ ‐‐> Ashley_

img_ ‐‐> Ashley_

模板的另一个应用是把多样的输出格式细节从程序逻辑中分类出来。这便使得 XML 文

件,纯文本报表和 HTML WEB 报表定制模板成为可能。

11.3. 使用二进制数据记录布局

struct 模块为使用变长的二进制记录格式提供了 pack() 和 unpack() 函数。下面的示例

演示了在不使用 zipfile 模块的情况下如何迭代一个 ZIP 文件的头信息。压缩码

"H"

"I"

分别表示2和4字节无符号数字,

"<"

表明它们都是标准大小并且按照 little-

endian 字节排序。

import struct

with open('', 'rb') as f:

data = ()

start = 0

for i in range(3): # show the first 3 file headers

start += 14

fields = ('

crc32, comp_size, uncomp_size, filenamesize, extra_size = fields

start += 16

filename = data[start:start+filenamesize]

start += filenamesize

extra = data[start:start+extra_size]

print(filename, hex(crc32), comp_size, uncomp_size)

start += extra_size + comp_size # skip to the next header

11.4. 多线程

线程是一个分离无顺序依赖关系任务的技术。在某些任务运行于后台的时候应用程序

会变得迟缓,线程可以提升其速度。一个有关的用途是在 I/O 的同时其它线程可以并行

计算。

下面的代码显示了高级模块 threading 如何在主程序运行的同时运行任务:

import threading, zipfile

class AsyncZip():

def __init__(self, infile, outfile):

.__init__(self)

= infile

e = outfile

def run(self):

f = e(e, 'w', _DEFLATED)

()

()

print('Finished background zip of:', )

background = AsyncZip('', '')

()

print('The main program continues to run in foreground.')

() # Wait for the background task to finish

print('Main program waited until background was done.')

多线程应用程序的主要挑战是协调线程,诸如线程间共享数据或其它资源。为了达到

那个目的,线程模块提供了许多同步化的原生支持,包括:锁,事件,条件变量和信

号灯。

尽管这些工具很强大,微小的设计错误也可能造成难以挽回的故障。因此,任务协调

的首选方法是把对一个资源的所有访问集中在一个单独的线程中,然后使用 queue 模

块用那个线程服务其他线程的请求。为内部线程通信和协调而使用 Queue 对象的应用

程序更易于设计,更可读,并且更可靠。

11.5. 日志

logging 模块提供了完整和灵活的日志系统。它最简单的用法是记录信息并发送到一个

文件或

:

import logging

('Debugging information')

('Informational message')

g('Warning:config file %s not found', '')

('Error occurred')

al('Critical error ‐‐ shutting down')

输出如下:

WARNING:root:Warning:config file not found

ERROR:root:Error occurred

CRITICAL:root:Critical error ‐‐ shutting down

默认情况下捕获信息和调试消息并将输出发送到标准错误流。其它可选的路由信息方

式通过 email,数据报文,socket 或者 HTTP Server。基于消息属性,新的过滤器可以

选择不同的路由:

DEBUG

INFO

WARNING

ERROR

CRITICAL

日志系统可以直接在 Python 代码中定制,也可以不经过应用程序直接在一个用户可编

辑的配置文件中加载。

11.6. 弱引用

Python 自动进行内存管理(对大多数的对象进行引用计数和垃圾回收—— 垃圾回收

——以循环利用)在最后一个引用消失后,内存会很快释放。

这个工作方式对大多数应用程序工作良好,但是偶尔会需要跟踪对象来做一些事。不

幸的是,仅仅为跟踪它们创建引用也会使其长期存在。 weakref 模块提供了不用创建

引用的跟踪对象工具,一旦对象不再存在,它自动从弱引用表上删除并触发回调。典

型的应用包括捕获难以构造的对象:

>>> import weakref, gc

>>> class A:

... def __init__(self, value):

... = value

... def __repr__(self):

... return str()

...

>>> a = A(10) # create a reference

>>> d = lueDictionary()

>>> d['primary'] = a # does not create a reference

>>> d['primary'] # fetch the object if it is still alive

10

>>> del a # remove the one reference

>>> t() # run garbage collection right away

0

>>> d['primary'] # entry was automatically removed

Traceback (most recent call last):

File "", line 1, in

d['primary'] # entry was automatically removed

File "C:/python34/lib/", line 46, in __getitem__

o = [key]()

KeyError: 'primary'

11.7. 列表工具

很多数据结构可能会用到内置列表类型。然而,有时可能需要不同性能代价的实现。

array 模块提供了一个类似列表的 array() 对象,它仅仅是存储数据,更为紧凑。以下的

示例演示了一个存储双字节无符号整数的数组(类型编码

"H"

)而非存储 16 字节

Python 整数对象的普通正规列表:

>>> from array import array

>>> a = array('H', [4000, 10, 700, 22222])

>>> sum(a)

26932

>>> a[1:3]

array('H', [10, 700])

collections 模块提供了类似列表的 deque() 对象,它从左边添加(append)和弹出

(pop)更快,但是在内部查询更慢。这些对象更适用于队列实现和广度优先的树搜索:

>>> from collections import deque

>>> d = deque(["task1", "task2", "task3"])

>>> ("task4")

>>> print("Handling", t())

Handling task1

unsearched = deque([starting_node])

def breadth_first_search(unsearched):

node = t()

for m in gen_moves(node):

if is_goal(m):

return m

(m)

除了链表的替代实现,该库还提供了 bisect 这样的模块以操作存储链表:

>>> import bisect

>>> scores = [(100, 'perl'), (200, 'tcl'), (400, 'lua'), (500, 'python')]

>>> (scores, (300, 'ruby'))

>>> scores

[(100, 'perl'), (200, 'tcl'), (300, 'ruby'), (400, 'lua'), (500, 'python')]

heapq 提供了基于正规链表的堆实现。最小的值总是保持在 0 点。这在希望循环访问最

小元素但是不想执行完整堆排序的时候非常有用:

>>> from heapq import heapify, heappop, heappush

>>> data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]

>>> heapify(data) # rearrange the list into heap order

>>> heappush(data, ‐5) # add a new entry

>>> [heappop(data) for i in range(3)] # fetch the three smallest entries

[‐5, 0, 1]

11.8. 十进制浮点数算法

decimal 模块提供了一个 Decimal 数据类型用于浮点数计算。相比内置的二进制浮点数

实现 float,这个类型有助于

金融应用和其它需要精确十进制表达的场合,

控制精度,

控制舍入以适应法律或者规定要求,

确保十进制数位精度,

或者

用户希望计算结果与手算相符的场合。

例如,计算 70 分电话费的 5% 税计算,十进制浮点数和二进制浮点数计算结果的差别

如下。如果在分值上舍入,这个差别就很重要了:

>>> from decimal import *

>>> round(Decimal('0.70') * Decimal('1.05'), 2)

Decimal('0.74')

>>> round(.70 * 1.05, 2)

0.73

Decimal 的结果总是保有结尾的 0,自动从两位精度延伸到4位。Decimal 重现了手工的

数学运算,这就确保了二进制浮点数无法精确保有的数据精度。

高精度使 Decimal 可以执行二进制浮点数无法进行的模运算和等值测试:

>>> Decimal('1.00') % Decimal('.10')

Decimal('0.00')

>>> 1.00 % 0.10

0.99995

>>> sum([Decimal('0.1')]*10) == Decimal('1.0')

True

>>> sum([0.1]*10) == 1.0

False

decimal 提供了必须的高精度算法:

>>> getcontext().prec = 36

>>> Decimal(1) / Decimal(7)

Decimal('0.777')

Docs » 12. 虚拟环境和包

12. 虚拟环境和包

12.1. 简介

Python 应用程序经常会使用一些不属于标准库的包和模块。应用程序有时候需要某个

特定版本的库,因为它需要一个特定的 bug 已得到修复的库或者它是使用了一个过时

版本的库的接口编写的。

这就意味着可能无法安装一个 Python 来满足每个应用程序的要求。如果应用程序 A 需

要一个特定模块的 1.0 版本但是应用程序 B 需要该模块的 2.0 版本,这两个应用程序的

要求是冲突的,安装版本 1.0 或者版本 2.0 将会导致其中一个应用程序不能运行。

这个问题的解决方案就是创建一个 虚拟环境 (通常简称为 “virtualenv”),包含一个特

定版本的 Python,以及一些附加的包的独立的目录树。

不同的应用程序可以使用不同的虚拟环境。为了解决前面例子中的冲突,应用程序 A

可以有自己的虚拟环境,其中安装了特定模块的 1.0 版本。而应用程序 B 拥有另外一个

安装了特定模块 2.0 版本的虚拟环境。如果应用程序 B 需求一个库升级到 3.0 的话,这

也不会影响到应用程序 A 的环境。

12.2. 创建虚拟环境

用于创建和管理虚拟环境的脚本叫做 pyvenv。pyvenv 通常会安装你可用的 Python 中

最新的版本。这个脚本也能指定安装一个特定的版本的 Python,因此如果在你的系统

中有多个版本的 Python 的话,你可以运行

pyvenv‐3.5

或者你想要的任何版本来选择一

个指定的 Python 版本。

要创建一个 virtualenv,首先决定一个你想要存放的目录接着运行 pyvenv 后面携带着

目录名:

pyvenv tutorial‐env

如果目录不存在的话,这将会创建一个

tutorial‐env

目录,并且也在目录里面创建一

个包含 Python 解释器,标准库,以及各种配套文件的 Python “副本”。

一旦你已经创建了一个虚拟环境,你必须激活它。

在 Windows 上,运行:

tutorial‐env/Scripts/activate

在 Unix 或者 MacOS 上,运行:

source tutorial‐env/bin/activate

(这个脚本是用 bash shell 编写的。如果你使用 csh 或者 fish shell,你应该使用

来替代。)

激活了虚拟环境会改变你的 shell 提示符,显示你正在使用的虚拟环境,并且修改了环

境以致运行

python

将会让你得到了特定的 Python 版本。例如:

‐> source ~/envs/tutorial‐env/bin/activate

(tutorial‐env) ‐> python

Python 3.5.2+ (3.4:c7b9645a6f35+, May 22 2015, 09:31:25)

...

>>> import sys

>>>

['', '/usr/local/lib/', ...,

'~/envs/tutorial‐env/lib/python3.5/site‐packages']

>>>

12.3. 使用 pip 管理包

一旦你激活了一个虚拟环境,可以使用一个叫做 pip 程序来安装,升级以及删除包。默

认情况下

pip

将会从 Python Package Index,, 中安

pip

装包。你可以通过 web 浏览器浏览它们,或者你也能使用 有限的搜索功能:

(tutorial‐env) ‐> pip search astronomy

skyfield ‐ Elegant astronomy for Python

gary ‐ Galactic astronomy and gravitational dynamics.

novas ‐ The United States Naval Observatory NOVAS astronomy library

astroobs ‐ Provides astronomy ephemeris to plan telescope observations

PyAstronomy ‐ A collection of astronomy related tools for Python.

...

pip

有许多子命令:“搜索”,“安装”,“卸载”,“freeze”(译者注:这个词语暂时没有合

pip

适的词语来翻译),等等。(请参考 installing-index 指南获取

档。)

你可以安装一个包最新的版本,通过指定包的名称:

更多完整的文

‐> pip install novas

Collecting novas

Downloading novas‐ (136kB)

Installing collected packages: novas

Running install for novas

Successfully installed novas‐3.1.1.3

你也能安装一个指定版本的包,通过给出包名后面紧跟着

==

和版本号:

‐> pip install requests==2.6.0

Collecting requests==2.6.0

Using cached requests‐2.6.0‐3‐none‐

Installing collected packages: requests

Successfully installed requests‐2.6.0

如果你重新运行命令(pip install requests==2.6.0),

pip install ‐‐upgrade

pip

会注意到要求的版本已经安

装,不会去做任何事情。你也可以提供一个不同的版本号来安装,或者运行

来升级包到最新版本:

‐> pip install ‐‐upgrade requests

Collecting requests

Installing collected packages: requests

Found existing installation: requests 2.6.0

Uninstalling requests‐2.6.0:

Successfully uninstalled requests‐2.6.0

Successfully installed requests‐2.7.0

pip uninstall

后跟一个或者多个包名将会从虚拟环境中移除这些包。

pip show

将会显示一个指定的包的信息:

(tutorial‐env) ‐> pip show requests

‐‐‐

Metadata‐Version: 2.0

Name: requests

Version: 2.7.0

Summary: Python HTTP for Humans.

Home‐page: python‐

Author: Kenneth Reitz

Author‐email: me@

License: Apache 2.0

Location: /Users/akuchling/envs/tutorial‐env/lib/python3.4/site‐packages

Requires:

pip list

将会列出所有安装在虚拟环境中的包:

(tutorial‐env) ‐> pip list

novas (3.1.1.3)

numpy (1.9.2)

pip (7.0.3)

requests (2.7.0)

setuptools (16.0)

pip freeze

将会生成一个类似需要安装的包的列表,但是输出采用了

pip install

期望

的格式。常见的做法就是把它们放在一个 文件:

(tutorial‐env) ‐> pip freeze >

(tutorial‐env) ‐> cat

novas==3.1.1.3

numpy==1.9.2

requests==2.7.0

能够被提交到版本控制中并且作为一个应用程序的一部分。用户们可

安装所有必须的包:以使用

install ‐r

‐> pip install ‐r

Collecting novas==3.1.1.3 (from ‐r (line 1))

...

Collecting numpy==1.9.2 (from ‐r (line 2))

...

Collecting requests==2.7.0 (from ‐r (line 3))

...

Installing collected packages: novas, numpy, requests

Running install for novas

Successfully installed novas‐3.1.1.3 numpy‐1.9.2 requests‐2.7.0

pip

还有更多的选项。请参考 installing-index 指南获取关于

pip

完整的文档。当你编

写一个包并且在 Python Package Index 中也出现的话,请参考 distributing-index 指

南。

Docs » 13. 接下来?

13. 接下来?

读过这本指南应该会让你有兴趣使用 Python —— 可能你已经期待着用 Python 解决你的

实际问题了。可以在哪里进行一步学习?

入门指南是 Python 文档集的一部分。其中的另一些文档包括:

Python 标准库:

应该浏览一下这份文档,它为标准库中的类型、函数和模块提供了完整(尽管很简

略)的参考资料。标准的 Python 发布版包括了 大量 的附加模块。其中有针对读取

Unix 邮箱、接收 HTTP 文档、生成随机数、解析命令行选项、写 CGI 程序、压缩数

据以及很多其它任务的模块。略读一下库参考会给你很多解决问题的思路。

安装 Python 模块 展示了如何安装其他 Python 用户编写的附加模块。

Python 语言参考: 詳細说明了 Python 语法和语义。

它读起来很累,不过对于语言本身,有份完整的手册很有用。

其它 Python 资源:

: Python 官方网站。它包含代码、文档和 Web 上与

Python 有关的页面链接该网站镜像于全世界的几处其它问题,类似欧洲、日本和澳

大利亚。

镜像可能会比主站快,这取决于你的地理位置。

: 快速访问 Python 的文档。

: Python 包索引,以前昵称为奶酪店,索引了可供下载的,

用户创建的 Python 模块。如果你发布了代码,可以注册到这里,这样别人可以找

到它。

/recipes/langs/python/: Python 食谱是大量的示例代

码、大型的集合,和有用的脚本。

值得关注的是这次资源已经结集成书,名为《Python 食谱》(O’Reilly &

Associates, ISBN 0-596-00797-3。)

: The Scientific Python 项目包括数组快速计算和处理模块,和大量

线性代数、傅里叶变换、非线性solvers、随机数分布,统计分析以及类似的包。

与 Python 有关的问题,以及问题报告,可以发到新闻组 ,或者发送

到邮件组 python-list@ 。新闻组和邮件组是开放的,所以发送的消息可以自

动的跟到另一个之后。每天有超过 120 个投递(高峰时有数百),提问(以及回答)问

题,为新功能提建议,发布新模块。在发信之前,请查阅 常见问题 (亦称 FAQ),或者

在 Python 源码发布包的

Misc/

目录中查阅。邮件组也可以在

/pipermail/ 访问。FAQ回答了很多被反复提到的问题,很可能已

经解答了你的问题。

Docs » 14. 交互式输入行编辑历史回溯

14. 交互式输入行编辑历史回溯

某些版本的 Python 解释器支持编辑当前的输入行和历史记录,类似于在 Korn shell 和

GNU Bash shell 中看到的功能。这是使用 GNU Readline 库实现的,它支持各种编辑风

格。 这个库有它自己的文档,在这里我们不就重复了。

14.1. Tab 补全和历史记录

变量和模块名的补全在解释器启动时 自动打开 以便

Tab

键调用补全功能;它会查看

Python语句的名字,当前局部变量以及可以访问的模块名。对于点分表达式如

string.a

,它将求出表达式最后一个

'.'

之前的值,然后根据结果的属性给出补全的

建议。注意,如果一个具有 __getattr__() 方法的对象是表达式的某部分,这可能执行应

用程序定义的代码。默认的配置同时会把历史记录保存在你的用户目录下一个名为

.python_history

的文件中。在下次与交互式解释器的会话中,历史记录将还可以访

问。

14.2. 其它交互式解释器

与早期版本的解释器相比,现在是向前巨大的进步;然而,有些愿望还是没有实现:

如果能对连续的行给出正确的建议就更好了(解析器知道下一行是否需要缩进)。补

全机制可以使用解释器的符号表。检查(或者只是建议)匹配的括号、 引号的命令等

也会非常有用。

一个增强的交互式解释器是 IPython,它已经存在相当一段时间,具有 tab 补全、 对象

exploration 和高级的历史记录功能。它也可以彻底定制并嵌入到其他应用程序中。另

一个类似的增强的交互式环境是 bpython。

Docs » 15. 浮点数算法:争议和限制

15. 浮点数算法:争议和限制

浮点数在计算机中表达为二进制(binary)小数。例如:十进制小数:

0.125

是 1/10 + 2/100 + 5/1000 的值,同样二进制小数:

0.001

是 0/2 + 0/4 + 1/8。这两个数值相同。唯一的实质区别是第一个写为十进制小数记法,

第二个是二进制。

不幸的是,大多数十进制小数不能完全用二进制小数表示。结果是,一般情况下,你

输入的十进制浮点数仅由实际存储在计算机中的近似的二进制浮点数表示。

这个问题更早的时候首先在十进制中发现。考虑小数形式的 1/3 ,你可以来个十进制的

近似值。

0.3

或者更进一步的,

0.33

或者更进一步的,

0.333

诸如此类。如果你写多少位,这个结果永远不是精确的 1/3 ,但是可以无限接近 1/3 。

同样,无论在二进制中写多少位,十进制数 0.1 都不能精确表达为二进制小数。二进制

来表达 1/10 是一个无限循环小数:

在任何有限数量的位停下来,你得到的都是近似值。今天在大多数机器上,浮点数的

近似使用的小数以最高的 53 位为分子,2 的幂为分母。至于 1/10 这种情况,其二进制

小数是

3697 / 2 ** 55

,它非常接近但不完全等于1/10真实的值。

由于显示方式的原因,许多使用者意识不到是近似值。Python 只打印机器中存储的二

进制值的十进制近似值。在大多数机器上,如果 Python 要打印 0.1 存储的二进制的真

正近似值,将会显示:

>>> 0.1

0.41015625

这么多位的数字对大多数人是没有用的,所以 Python 显示一个舍入的值

>>> 1 / 10

0.1

只要记住即使打印的结果看上去是精确的 1/10,真正存储的值是最近似的二进制小

数。

有趣地是,存在许多不同的十进制数共享着相同的近似二进制小数。例如,数字

0.10001

0.1

以及

0.41015625

3697 / 2 ** 55

的近似值。因为所有这些十进制数共享相同的近似值,在

的同时,显示的可能是它们中的任何一个。保持恒等式

eval(repr(x)) == x

历史上,Python 提示符和内置的 repr() 函数选择一个 17 位精度的数

字,

0.10001

。从 Python 3.1 开始,Python(在大多数系统上)能够从这些

0.1

数字当中选择最短的一个并简单地显示 。

注意,这是二进制浮点数的自然性质:它不是 Python 中的一个 bug,也不是你的代码

中的 bug。你会看到所有支持硬件浮点数算法的语言都会有这个现象(尽管有些语言默

认情况下或者在所有输出模式下可能不会 显示 出差异)。

为了输出更好看,你可能想用字符串格式化来生成固定位数的有效数字:

>>> format(, '.12g') # give 12 significant digits

'3.'

>>> format(, '.2f') # give 2 digits after the point

'3.14'

>>> repr()

'3.9793'

认识到这,在真正意义上,是一种错觉是很重要的:你在简单地舍入真实机器值的 显

示。

例如,既然 0.1 不是精确的 1/10,3 个 0.1 的值相加可能也不会得到精确的 0.3:

>>> .1 + .1 + .1 == .3

False

另外,既然 0.1 不能更接近 1/10 的精确值而且 0.3 不能更接近 3/10 的精确值,使用

round() 函数提前舍入也没有帮助:

>>> round(.1, 1) + round(.1, 1) + round(.1, 1) == round(.3, 1)

False

虽然这些数字不可能再更接近它们想要的精确值,round() 函数可以用于在计算之后进

行舍入,这样的话不精确的结果就可以和另外一个相比较了:

>>> round(.1 + .1 + .1, 10) == round(.3, 10)

True

二进制浮点数计算有很多这样意想不到的结果。“0.1”的问题在下面”误差的表示”一节中

有准确详细的解释。更完整的常见怪异现象请参见 浮点数的危险。

最后我要说,“没有简单的答案”。也不要过分小心浮点数!Python 浮点数计算中的误

差源之于浮点数硬件,大多数机器上每次计算误差不超过 2**53 分之一。对于大多数任

务这已经足够了,但是你要在心中记住这不是十进制算法,每个浮点数计算可能会带

来一个新的舍入错误。

虽然确实有问题存在,对于大多数平常的浮点数运算,你只要简单地将最终显示的结

果舍入到你期望的十进制位数,你就会得到你期望的最终结果。str() 通常已经足够用

了,对于更好的控制可以参阅 格式化字符串语法 中 () 方法的格式说明符。

对于需要精确十进制表示的情况,可以尝试使用 decimal 模块,它实现的十进制运算适

合会计方面的应用和高精度要求的应用。

fractions 模块支持另外一种形式的运算,它实现的运算基于有理数(因此像1/3这样的

数字可以精确地表示)。

如果你是浮点数操作的重度使用者,你应该看一下由 SciPy 项目提供的 Numerical

Python 包和其它用于数学和统计学的包。参看 <>。

当你真的 真 想要知道浮点数精确值的时候,Python 提供这样的工具可以帮助

你。_integer_ratio() 方法以分数的形式表示一个浮点数的值:

>>> x = 3.14159

>>> _integer_ratio()

(35379, 42624)

因为比值是精确的,它可以用来无损地重新生成初始值:

>>> x == 35379 / 42624

True

() 方法以十六进制表示浮点数,给出的同样是计算机存储的精确值:

>>> ()

'0x1.921f9f01b866ep+1'

精确的十六进制表示可以用来准确地重新构建浮点数:

>>> x == x('0x1.921f9f01b866ep+1')

True

因为可以精确表示,所以可以用在不同版本的 Python(与平台相关)之间可靠地移植

数据以及与支持同样格式的其它语言(例如 Java 和 C99)交换数据。

另外一个有用的工具是 () 函数,它帮助求和过程中减少精度的损失。当数值

在不停地相加的时候,它会跟踪“丢弃的数字”。这可以给总体的准确度带来不同,以至

于错误不会累积到影响最终结果的点:

>>> sum([0.1] * 10) == 1.0

False

>>> ([0.1] * 10) == 1.0

True

15.1. 表达错误

这一节详细说明 “0.1” 示例,教你怎样自己去精确的分析此类案例。假设这里你已经对

浮点数表示有基本的了解。

Representation error 提及事实上有些(实际是大多数)十进制小数不能精确的表示为二

进制小数。这是 Python (或 Perl,C,C++,Java,Fortran 以及其它很多)语言往往

不能按你期待的样子显示十进制数值的根本原因。

这是为什么? 1/10 不能精确的表示为二进制小数。大多数今天的机器(2000年十一

月)使用 IEEE-754 浮点数算法,大多数平台上 Python 将浮点数映射为 IEEE-754 “双精

度浮点数”。754 双精度包含 53 位精度,所以计算机努力将输入的 0.1 转为 J/2**N 最接

近的二进制小数。J 是一个 53 位的整数。改写:

1 / 10 ~= J / (2**N)

为:

J ~= 2**N / 10

J 重现时正是 53 位(是

>= 2**52

而非

< 2**53

), N 的最佳值是 56:

>>> 2**52 <= 2**56 // 10 < 2**53

True

因此,56 是保持 J 精度的唯一 N 值。J 最好的近似值是整除的商:

>>> q, r = divmod(2**56, 10)

>>> r

6

因为余数大于 10 的一半,最好的近似是取上界:

>>> q+1

7294

因此在 754 双精度中 1/10 最好的近似值是是 2**56,或:

7294 / 2 ** 56

分子和分母都除以2将小数缩小到:

3697 / 2 ** 55

要注意因为我们向上舍入,它其实比 1/10 稍大一点点。如果我们没有向上舍入,它会

比 1/10 稍小一点。但是没办法让它 恰好 是 1/10!

所以计算机永远也不 “知道” 1/10:它遇到上面这个小数,给出它所能得到的最佳的

754 双精度实数:

>>> .1 * 2**55

7294.0

如果我们把这小数乘以 10**55,我们可以看到其55位十进制数的值:

>>> 3697 * 10 ** 55 // 2 ** 55

41015625

这表示存储在计算机中的实际值近似等于十进制值

0.41015625。许多语言

(包括旧版本的Python)会把结果舍入到 17 位有效数字,而不是显示全部的十进制值:

>>> format(0.1, '.17f')

'0.10001'

fractions 和 decimal 模块使得这些计算很简单:

>>> from decimal import Decimal

>>> from fractions import Fraction

>>> _float(0.1)

Fraction(3697, 36968)

>>> (0.1).as_integer_ratio()

(3697, 36968)

>>> _float(0.1)

Decimal('0.41015625')

>>> format(_float(0.1), '.17')

'0.10001'

Docs » 16. 附录

16. 附录

16.1. 交互模式

16.1.1. 错误处理

当错误发生时,解释器打印一个错误信息和堆栈跟踪。在交互模式下,它返回主提示

符;当输入来自文件的时候,在打印堆栈跟踪后以非零退出(a nonzero exit)状态退出。

(在 try 声明中被 except 子句捕捉到的异常在这种情况下不是错误。)有些错误是非

常致命的会导致一个非零状态的退出;这也适用于内部错误以及某些情况的内存耗

尽。所有的错误信息都写入到标准错误流;来自执行的命令的普通输出写入到标准输

出。

输入中断符(通常是 Control-C 或者 DEL)到主或者从提示符中会取消输入并且返回到

主提示。

[1]

当命令执行中输入中断符会引起 KeyboardInterrupt 异常,这个异常能够

被一个 try 声明处理。

16.1.2. 可执行 Python 脚本

在 BSD’ish Unix 系统上,Python 脚本可直接执行,像 shell 脚本一样,只需要把下面内

容加入到

#!/usr/bin/env python3.5

(假设 python 解释器在用户的

式。

符(

#!

'n'

PATH

中)脚本的开头,并给予该文件的可执行模

'rn'

必须是文件的头两个字符。在一些系统上,第一行必须以 Unix-style 的行结束

)结束,不能以 Windows 的行结束符()。 注意

'#'

在 Python 中

是用于注释的。

使用 chmod 命令能够给予脚本执行模式或者权限。

$ chmod +x

在 Windows 系统上,没有一个 “可执行模式” 的概念。Python 安装器会自动地把

文件和

.pyw

.py

关联起来,因此双击 Python 将会把它当成一个脚本运行。文件扩展

名也可以是 ,在这种情况下,运行时不会出现控制台窗口。

16.1.3. 交互式启动文件

当你使用交互式 Python 的时候,它常常很方便地执行一些命令在每次解释器启动时。

你可以这样做:设置一个名为 PYTHONSTARTUP 的环境变量为包含你的启动命令的文

件名。这跟 Unix shells 的

.profile

特点有些类似。

这个文件在交互式会话中是只读的,在当 Python 从脚本中读取命令,以及在当

/dev/tty

被作为明确的命令源的时候不只是可读的。该文件在交互式命令被执行的时

候在相同的命名空间中能够被执行,因此在交互式会话中定义或者导入的对象能够无

需授权就能使用。你也能在文件中更改提示

1

2

如果你想要从当前目录中读取一个附加的启动文件,你可以在全局启动文件中编写代

码像这样:

if ('.'): exec(open('.').read())

。如果你

想要在脚本中使用启动文件的话,你必须在脚本中明确要这么做:

import os

filename = ('PYTHONSTARTUP')

if filename and (filename):

with open(filename) as fobj:

startup_file = ()

exec(startup_file)

16.1.4. 定制模块

Python 提供两个钩子为了让你们定制

运行这段代码:

sitecustomize

usercustomize

。为了看看它的

工作机制的话,你必须首先找到你的用户 site-packages 目录的位置。启动 Python 并且

>>> import site

>>> rsitepackages()

'/home/user/.local/lib/python3.4/site‐packages'

现在你可以创建一个名为

的文件在你的用户 site-packages 目录,并

且在里面放置你想要的任何内容。它会影响 Python 的每一次调用,除非它以 -s (禁用

自动导入)选项启动。

sitecustomize

以同样地方式工作,但是通常由是机器的管理员创建在全局的 site-

usercustomize

packages 目录中,并且是在

Footnotes

[1]

之前导入。请参阅 site 模块获取更多信息。

GNU 的 Readline 包的问题可能会阻止这种做法。


本文标签: 模块 浮点数 提供 使用 可能