楼主: lastwinner

[参考文档] Python 研究(Dive Into Python)

[复制链接]
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
301#
 楼主| 发表于 2006-7-19 00:51 | 只看该作者
例 16.2. regression.py 的范例输出
[you@localhost py]$ python regression.py -v
help should fail with no object ... ok                             
help should return known result for apihelper ... ok
help should honor collapse argument ... ok
help should honor spacing argument ... ok
buildConnectionString should fail with list input ... ok           
buildConnectionString should fail with string input ... ok
buildConnectionString should fail with tuple input ... ok
buildConnectionString handles empty dictionary ... ok
buildConnectionString returns known result with known input ... ok
fromRoman should only accept uppercase input ... ok               
toRoman should always return uppercase ... ok
fromRoman should fail with blank string ... ok
fromRoman should fail with malformed antecedents ... ok
fromRoman should fail with repeated pairs of numerals ... ok
fromRoman should fail with too many repeated numerals ... ok
fromRoman should give known result with known input ... ok
toRoman should give known result with known input ... ok
fromRoman(toRoman(n))==n for all n ... ok
toRoman should fail with non-integer input ... ok
toRoman should fail with negative input ... ok
toRoman should fail with large input ... ok
toRoman should fail with 0 input ... ok
kgp a ref test ... ok
kgp b ref test ... ok
kgp c ref test ... ok
kgp d ref test ... ok
kgp e ref test ... ok
kgp f ref test ... ok
kgp g ref test ... ok

----------------------------------------------------------------------
Ran 29 tests in 2.799s

OK  前五个测试来自于 apihelpertest.py,用以测试 第 4 章 自省的威力 中的范例代码。
  接下来的五个代码来自于 odbchelpertest.py, 用以测试 第 2 章 第一个 Python 程序 中的范例代码。
  其他的代码来自于 romantest.py,你在 第 13 章 单元测试 中深入学习过。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
302#
 楼主| 发表于 2006-7-19 00:52 | 只看该作者
16.2. 找到路径
从命令行运行 Python 代码时,知道所运行代码所在磁盘上的存储位置有时候是有必要的。

这是一个你很难自己弄明白,却一看到就会想起的小麻烦。核心功能来源于 sys.argv。正如你在 第 9 章 XML 处理 中看到的,它包含了很多命令行参数。 当然就像从命令行中运行他们一样,它也同样记录了运行脚本的名字,这些信息足以令我们确定文件的位置。

例 16.3. fullpath.py
如果您还没有下载本书附带的例子程序, 可以 下载本程序和其他例子程序。


import sys, os

print 'sys.argv[0] =', sys.argv[0]            
pathname = os.path.dirname(sys.argv[0])        
print 'path =', pathname
print 'full path =', os.path.abspath(pathname)   无论如何运行一段脚本, sys.argv[0] 总是像通过命令行调用一样,需要包含脚本的名字。你很快会发现,它不一定包含任何路径信息。
  os.path.dirname 接受作为字符串传来的文件名并返回路径部分。如果给定的文件名不包含任何路径信息, os.path.dirname 返回空字符串。
  os.path.abspath 是这里的关键。 它接受的路径名可以是部分的甚至是完全空白,却返回完整有效的路径名。

进一步的解释 os.path.abspath 是有必要的。 它非常灵活,可以接受任何类型的路径名。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
303#
 楼主| 发表于 2006-7-19 00:52 | 只看该作者
例 16.4. os.path.abspath 的进一步解释
>>> import os
>>> os.getcwd()                        
/home/you
>>> os.path.abspath('')               
/home/you
>>> os.path.abspath('.ssh')            
/home/you/.ssh
>>> os.path.abspath('/home/you/.ssh')
/home/you/.ssh
>>> os.path.abspath('.ssh/../foo/')   
/home/you/foo  os.getcwd() 返回当前的工作路径。
  一个空字符串调用 os.path.abspath 当前的工作路径,与 os.getcwd()的效果相同。
  以不完整的路径名调用 os.path.abspath 可以构建一个基于当前工作路径且完整有效的路径名。
  以完整的路径名调用 os.path.abspath 则简单地将其直接返回。
  os.path.abspath 还 格式化 返回的路径名。 注意这个例子在我根本没有‘foo’目录时同样奏效。 os.path.abspath 从不检查你的磁盘,而仅仅是字符串操作。


传递给 os.path.abspath 的路径名和文件名可以不存在。

os.path.abspath 不仅构建完整路径名,还能格式化路径名。 这意味着如果你正工作于 /usr/ 目录, os.path.abspath('bin/../local/bin') 将会返回 /usr/local/bin 。 它以尽可能简单的方式格式化路径名。 如果你只是希望简单地返回这样的格式化路径名而不需要完整路径名可以使用 os.path.normpath。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
304#
 楼主| 发表于 2006-7-19 00:52 | 只看该作者
例 16.5. fullpath.py 的范例输出
[you@localhost py]$ python /home/you/diveintopython/common/py/fullpath.py
sys.argv[0] = /home/you/diveintopython/common/py/fullpath.py
path = /home/you/diveintopython/common/py
full path = /home/you/diveintopython/common/py
[you@localhost diveintopython]$ python common/py/fullpath.py               
sys.argv[0] = common/py/fullpath.py
path = common/py
full path = /home/you/diveintopython/common/py
[you@localhost diveintopython]$ cd common/py
[you@localhost py]$ python fullpath.py                                    
sys.argv[0] = fullpath.py
path =
full path = /home/you/diveintopython/common/py  在第一种情况下, sys.argv[0] 包含代码的完整路径。 你可以通过 os.path.dirname 函数将文件名从其中剥离出来并返回完整的路径, os.path.abspath 则是简单地把你传递给它的值返回。
  如果脚本是以不完整路名被运行的, sys.argv[0] 还是会包含命令行中应出现的一切。 os.path.dirname 将会给你一个(相对于当前工作路径的)不完整的路径名,os.path.abspath 将会以不完整路径名为基础构建一个完整的路径名。
  如果没有给定任何路径,而是从当前目录运行脚本, os.path.dirname 将简单地返回一个空字符串。 由于是从当前目录运行脚本, os.path.abspath 将针对给定的空字符串给出你所希望获知的当前目录。


就像 os 和 os.path 模块的其他函数, os.path.abspath 是跨平台的。 如果你是在 Windows (使用反斜杠作为路径符号)或 Mac OS (使用冒号)上运行,它们同样工作,只是将获得与我稍有不同的结果。 os 的所有函数都是这样的。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
305#
 楼主| 发表于 2006-7-19 00:52 | 只看该作者
补充. 一位读者对这个结果并不满意,他希望能够从当前路径运行所有单元测试,而不是从 regression.py 所在目录运行。 他建议以下面的代码加以取代:

例 16.6. 在当前目录运行脚本
import sys, os, re, unittest

def regressionTest():
    path = os.getcwd()      
    sys.path.append(path)   
    files = os.listdir(path)
  不是将 path 设置为运行代码所在的路径,而是将它设置为当前目录。可以是你在运行脚本之前所在的任何路径,而不需要是运行脚本所在的路径。(多次体味这句话,直到你真正理解了它)
  将这个目录添加到 Python 库搜索路径中,你稍后动态导入单元测试模块时, Python 就能找到它们了。 如果 path 就是正在运行代码的存储目录,你就不需要这样做了,因为 Python 总会查找这个目录。
  函数的其他部分不变。

这个技术允许你在多个项目中重用 regression.py 代码。 只需要将这个代码放在一个普通目录中,在运行项目前将路径更改为项目的目录。 所有项目的路径将被找到并进行测试工作,而不仅仅局限于 regression.py 所在目录的单元测试。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
306#
 楼主| 发表于 2006-7-19 00:53 | 只看该作者
16.3. 过滤已访问列表
你已经熟识了 应用列表遍历来过滤列表。 这里介绍的是达到相同效果的另一种令很多人感觉清晰的实现方法。

Python 有一个内建 filter 函数,它接受两个参数:一个函数和一个列表,返回一个列表。[7] 作为第一个参数传递给 filter 的函数本身应接受一个参数,filter 返回的列表将会包含被传入列表参数传递给 filter 所有可以另函数返回真(true)的元素。

都明白了吗?并没有听起来那么难。

例 16.7. 介绍 filter
>>> def odd(n):                 
...     return n % 2
...     
>>> li = [1, 2, 3, 5, 9, 10, 256, -3]
>>> filter(odd, li)            
[1, 3, 5, 9, -3]
>>> [e for e in li if odd(e)]   
>>> filteredList = []
>>> for n in li:               
...     if odd(n):
...         filteredList.append(n)
...     
>>> filteredList
[1, 3, 5, 9, -3]  odd 使用内建的取模(mod)函数 “%” 对于为奇数的 n 返回 True ;为偶数的返回 False 。
  filter 接受两个参数:一个函数(odd)和一个列表(li)。 它依列表循环为每个元素调用 odd 函数。 如果 odd 返回的是真(记住, Python 认为所有非零值为真),则该元素被放在返回列表中,如若不然则被过滤掉。 结果是一个只包含原列表中奇数的列表,出现顺序则和原列表相同。
  你可以通过遍历的方式完成相同的工作,正如在 第 4.5 节 “过滤列表” 中看到的。
  你可以通过 for 循环的方式完成相同的工作。 根据你编程的背景,这样也许更“直接”,但是像 filter 函数这样的实现方法更清晰。 不但编写简单,而且易于读懂。 for 循环就好比近距离的绘画:你可以看到所有的细节,但是或许你应该花几秒时间退后几步看一看图画的全景。 “啊,你仅仅是要过滤列表!”

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
307#
 楼主| 发表于 2006-7-19 00:53 | 只看该作者
例 16.8. regression.py 中的 filter
    files = os.listdir(path)                                
    test = re.compile("test\.py$", re.IGNORECASE)           
    files = filter(test.search, files)                        正如你在 第 16.2 节 “找到路径” 中看到的, path 可能包括正在运行脚本的完全或者部分路径名,或者当脚本运行自当前目录时包含一个空的字符串。 任何一种情况下, files 都会获得正运行脚本所在目录的文件名。
  这时一个复杂的正则表达式。正如你在 第 15.3 节 “重构”中看到的,如果你需要反复使用同一个正则表达式,你应该编译它已获得更快的性能。编译后的对象将含有接受一个被寻找字符串作为参数的 search 方法。 如果这个正则表达式匹配字符串, search 方法返回一个包含正则表达式匹配信息的 Match 对象;否则返回 None, 这是 Python 空(null) 值。
  对于 files 列表中的每个元素,你将会调用正则表达式编译对象 test 的 search 方法。 如果正则表达匹配,方法将会返回一个被 Python 认定为真(true)的 Match 对象;如果正则表达不匹配, search 方法将会返回被认定为假(false)的 None,元素将被排除。

历史注释. Python 2.0 早期的版本不包含 列表遍历,因此不能 以列表遍历方式过滤,filter 函数是当时唯一的方法。 即便是在引入列表遍历的 2.0 版,有些人仍然钟情于老派的 filter (和这章稍后将见到的它的伴侣函数 map ) 两种方法并存于世,使用哪种方法只是风格问题, map 和 filter 将在未来的 Python 版本中被废止的讨论尚无定论。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
308#
 楼主| 发表于 2006-7-19 00:53 | 只看该作者
例 16.9. 以列表遍历法过滤
    files = os.listdir(path)                              
    test = re.compile("test\.py$", re.IGNORECASE)         
    files = [f for f in files if test.search(f)]   这种方法将完成和 filter 函数完全相同的工作。 哪种方法更清晰完全取决于你自己。

Footnotes
[7] 从技术层面上讲, filter 的第二个参数可以是任意的序列,包括列表、元组以及定义了 __getitem__ 特殊方法而能像列表一样工作的自定义类。 在可能情况下, filter 会返回与输入相同的数据类型,也就是过滤一个列表返回一个列表,过滤一个元组返回一个元组。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
309#
 楼主| 发表于 2006-7-19 00:53 | 只看该作者
16.4. 关联已访问列表
你对使用 列表遍历 将列表关联起来的做法已经熟知。 另一种方法可以完成同样的工作:使用内建 map 函数。 它的工作机理和 filter 函数类似。

例 16.10. 介绍 map
>>> def double(n):
...     return n*2
...     
>>> li = [1, 2, 3, 5, 9, 10, 256, -3]
>>> map(double, li)                       
[2, 4, 6, 10, 18, 20, 512, -6]
>>> [double(n) for n in li]               
[2, 4, 6, 10, 18, 20, 512, -6]
>>> newlist = []
>>> for n in li:                          
...     newlist.append(double(n))
...     
>>> newlist
[2, 4, 6, 10, 18, 20, 512, -6]  map 接受一个函数和一个列表作为参数,[8] 并以列表中每个元素顺序地调用函数返回一个新的列表。 在这个例子中,函数仅仅是将每个元素乘以2。
  使用列表遍历的方法你可以做到相同的事情。 列表遍历是在 Python 2.0版时被引入的,map 便从此永远盘桓。
  你如果坚持以 Visual Basic 程序员而自居,通过 for 循环的方法完成相同的任务也完全可以。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
310#
 楼主| 发表于 2006-7-19 00:53 | 只看该作者
例 16.11. map 与混合数据类型的列表
>>> li = [5, 'a', (2, 'b')]
>>> map(double, li)                       
[10, 'aa', (2, 'b', 2, 'b')]  作为一个旁注,我想指出只要提供的那个函数能够正确处理各种数据类型, map 对于混合数据类型列表的处理同样出色。 在这里,这个 double 函数仅仅是将给定参数乘以 2 , Python 根据参数的数据类型决定 正确操作 的方法。 对整数而言,这意味着乘 2 ;对字符串而言,意味着把自身和自身连接;对于元组,意味着构建一个包括原始元组全部元素和原始元组组合在一起的新元组。

好了,玩够了。让我们来看一些真实代码。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表