楼主: 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
41#
 楼主| 发表于 2006-7-15 19:23 | 只看该作者
4.1. 概览
下面是一个完整可运行的 Python 程序。大概看一下这段程序,你应该可以理解不少了。用数字标出的行阐述了 第 2 章 第一个 Python 程序 中涉及的一些概念。如果剩下来的代码看起来有点奇怪,不用担心,通过阅读本章你将会理解所有这些。

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


def info(object, spacing=10, collapse=1):   
    """Print methods and doc strings.
   
    Takes module, class, list, dictionary, or string."""
    methodList = [method for method in dir(object) if callable(getattr(object, method))]
    processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
    print "\n".join(["%s %s" %
                      (method.ljust(spacing),
                       processFunc(str(getattr(object, method).__doc__)))
                     for method in methodList])

if __name__ == "__main__":                 
    print info.__doc__  该模块有一个声明为 info 的函数。根据它的 函数声明 可知,它有三个参数: object、spacing 和 collapse。实际上后面两个参数都是可选参数,关于这点你很快就会看到。
  info 函数有一个多行的 doc string,简要地描述了函数的功能。注意这里并没有提到返回值;单独使用这个函数只是为了这个函数产生的效果,并不是为了它的返回值。
  函数内的代码是缩进形式的。
  if __name__ 技巧允许这个程序在自己独立运行时做些有用的事情,同时又不妨碍作为其它程序的模块使用。 在这个例子中,程序只是简单地打印出 info 函数的 doc string。
  if 语句 使用 == 进行比较, 而且不需要括号。

info 函数的设计意图是提供给工作在 Python IDE 中的开发人员使用,它可以使用任何含有函数或者方法的对象(比如模块,含有函数,又比如list,含有方法)作为参数,并打印出对象的所有函数和它们的 doc string。

例 4.2. apihelper.py 的用法示例
>>> from apihelper import info
>>> li = []
>>> info(li)
append     L.append(object) -- append object to end
count      L.count(value) -> integer -- return number of occurrences of value
extend     L.extend(list) -- extend list by appending list elements
index      L.index(value) -> integer -- return index of first occurrence of value
insert     L.insert(index, object) -- insert object before index
pop        L.pop([index]) -> item -- remove and return item at index (default last)
remove     L.remove(value) -- remove first occurrence of value
reverse    L.reverse() -- reverse *IN PLACE*
sort       L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1缺省地,程序输出进行了格式化处理易于阅读。多行 doc string 被合并到单行中,要改变这个选项需要指定 collapse 参数的值为 0。如果函数名称长于10个字符,你可以将 spacing 参数的值指定为更大的值以使输出更容易阅读。

例 4.3. apihelper.py 的高级用法
>>> import odbchelper
>>> info(odbchelper)
buildConnectionString Build a connection string from a dictionary Returns string.
>>> info(odbchelper, 30)
buildConnectionString          Build a connection string from a dictionary Returns string.
>>> info(odbchelper, 30, 0)
buildConnectionString          Build a connection string from a dictionary
   
    Returns string.

使用道具 举报

回复
论坛徽章:
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
42#
 楼主| 发表于 2006-7-15 19:23 | 只看该作者
4.2. 使用可选参数和命名参数
Python 允许函数参数有缺省值;如果调用函数时不使用参数,参数将获得它的缺省值。此外,通过使用命名参数还可以以任意顺序指定参数。SQL Server Transact/SQL 中的存储过程也可以做到这些;如果你是脚本高手,你可以略过这部分。

info 函数就是这样一个例子,它有两个可选参数。


def info(object, spacing=10, collapse=1):spacing 和 collapse 是可选参数,因为它们已经定义了缺省值。object 是必备参数,因为它没有指定缺省值。如果调用 info 时只指定一个参数,那么 spacing 缺省为 10 ,collapse 缺省为 1。如果调用 info 时指定两个参数,collapse 依然默认为 1。

假如你要指定 collapse 的值,但是又想要接受 spacing 的缺省值。在绝大部分语言中,你可能运气就不太好了,因为你需要使用三个参数来调用函数,这势必要重新指定 spacing 的值。但是在 Python 中,参数可以通过名称以任意顺序指定。

例 4.4. info 的有效调用
info(odbchelper)                    
info(odbchelper, 12)               
info(odbchelper, collapse=0)        
info(spacing=15, object=odbchelper)   只使用一个参数,spacing 使用缺省值 10 ,collapse 使用缺省值 1。
  使用两个参数,collapse 使用缺省值 1。
  这里你显式命名了 collapse 并指定了它的值。spacing 将依然使用它的缺省值 10。
  甚至必备参数 (例如 object,没有指定缺省值) 也可以采用命名参数的方式, 而且命名参数可以以任意顺序出现。

这些看上去非常累,除非你意识到参数不过是一个字典。“通常” 不使用参数名称的函数调用只是一个简写的形式,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
43#
 楼主| 发表于 2006-7-15 19:23 | 只看该作者
4.3. 使用 type、str、dir 和其它内置函数
4.3.1. type 函数
4.3.2. str 函数
4.3.3. 内置函数
Python 有小部分相当有用的内置函数。除这些函数之外,其它所有的函数都被分到了各个模块中。其实这是一个非常明智的设计决策,避免了核心语言变得像其它脚本语言一样臃肿(咳 咳,Visual Basic)。

4.3.1. type 函数
type 函数返回任意对象的数据类型。在 types 模块中列出了可能的数据类型。这对于处理多种数据类型的帮助者函数非常有用。

例 4.5. type 介绍
>>> type(1)           
<type 'int'>
>>> li = []
>>> type(li)         
<type 'list'>
>>> import odbchelper
>>> type(odbchelper)  
<type 'module'>
>>> import types      
>>> type(odbchelper) == types.ModuleType
True  type 可以接收任何东西作为参数 -- 我的意思是任何东西 -- 并返回它的数据类型。整型、字符串、列表、字典、元组、函数、类、模块、甚至类型对象都可以作为参数被 type 函数接受。
  type 可以接收变量作为参数,并返回它的数据类型。
  type 还可以作用于模块。
  你可以使用 types 模块中的常量来进行对象类型的比较。这就是 info 函数所做的,很快你就会看到。

使用道具 举报

回复
论坛徽章:
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
44#
 楼主| 发表于 2006-7-15 19:24 | 只看该作者
4.3.2. str 函数
str 将数据强制转型为字符串。每种数据类型都可以强制转型为字符串。

例 4.6. str 介绍
>>> str(1)         
'1'
>>> horsemen = ['war', 'pestilence', 'famine']
>>> horsemen
['war', 'pestilence', 'famine']
>>> horsemen.append('Powerbuilder')
>>> str(horsemen)   
"['war', 'pestilence', 'famine', 'Powerbuilder']"
>>> str(odbchelper)
"<module 'odbchelper' from 'c:\\docbook\\dip\\py\\odbchelper.py'>"
>>> str(None)      
'None'  对于简单的数据类型比如整型,你可以预料到 str 的正常工作,因为几乎每种语言都有一个将整型转化为字符串的函数。
  然而 str 可以作用于任何数据类型的任何对象。这里它作用于一个零碎构建的列表。
  str 还允许作用于模块。注意模块的字符串形式表示包含了模块在磁盘上的路径名,所以你的显示结果将会有所不同。
  str 的一个细小但重要的行为是它可以作用于 None,None 是 Python 的 null 值。这个调用返回字符串 'None'。你将会使用这一点来提高你的 info 函数,这一点你很快就会看到。

info 函数的核心是强大的 dir 函数。dir 函数返回任意对象的属性和方法列表,包括模块对象、函数对象、字符串对象、列表对象、字典对象 …… 相当多的东西。

例 4.7. dir 介绍
>>> li = []
>>> dir(li)           
['append', 'count', 'extend', 'index', 'insert',
'pop', 'remove', 'reverse', 'sort']
>>> d = {}
>>> dir(d)            
['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'setdefault', 'update', 'values']
>>> import odbchelper
>>> dir(odbchelper)   
['__builtins__', '__doc__', '__file__', '__name__', 'buildConnectionString']  li 是一个列表,所以 dir(li) 返回所有列表方法的一个列表。注意返回的列表只包含了字符串形式的方法名称,而不是方法对象本身。
  d 是一个字典,所以 dir(d) 返回字典方法的名称列表。其中至少有一个方法,keys,看起来还是挺熟悉的。
  这里就是真正变得有趣的地方。odbchelper 是一个模块,所以 dir(odbchelper) 返回模块中定义的所有部件的列表,包括内置的属性,例如 __name__,__doc__, 以及其它你所定义的属性和方法。在这个例子中,odbchelper 只有一个用户定义的方法,就是在第 2 章中论述的 buildConnectionString 函数。

最后是 callable 函数,它接收任何对象作为参数,如果参数对象是可调用的那么返回 True,否则返回 False。可调用对象包括函数、类方法,甚至类自身。(下一章将更多的关注类)。

例 4.8. callable 介绍
>>> import string
>>> string.punctuation           
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
>>> string.join                  
<function join at 00C55A7C>
>>> callable(string.punctuation)
False
>>> callable(string.join)        
True
>>> print string.join.__doc__   
join(list [,sep]) -> string

    Return a string composed of the words in list, with
    intervening occurrences of sep.  The default separator is a
    single space.

    (joinfields and join are synonymous)  string 模块中的函数现在已经不赞成使用了(尽管很多人现在仍然还在使用 join 函数),但是在这个模块中包含了许多有用的变量比如 string.punctuation,这个模块包含了所有标准的标点符号字符。
  string.join 是一个用于连接字符串列表的函数。
  string.punctuation 是不可调用的对象;它是一个字符串。(字符串确有可调用的方法,但是字符串本身不是可调用的。)
  string.join 是可调用的;这个函数可以接受两个参数。
  任何可调用的对象都有 doc string。通过将 callable 函数作用于一个对象的每个属性,可以确定哪些属性(方法、函数、类)是你要关注的,哪些属性(常量等等)是你可以忽略、之前不需要知道的。

使用道具 举报

回复
论坛徽章:
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
45#
 楼主| 发表于 2006-7-15 19:24 | 只看该作者
4.3.3. 内置函数
type、str、dir 和其它的 Python 内置函数都归组到了 __builtin__ (前后分别是双下划线)这个特殊的模块中。如果有帮助的话,你可以认为 Python 在启动时自动执行了 from __builtin__ import *,此语句将所有的 “内置” 函数导入该命名空间,所以在这个命名空间中可以直接使用这些内置函数。

像这样考虑的好处是,是你可以获取 __builtin__ 模块信息的,并以组的形式访问所有的内置函数和属性。 猜到什么了吗,Python 有一个称为 info 的函数。自己尝试一下,略看一下结果列表。后面我们将深入到一些更重要的函数。(一些内置的错误类,比如 AttributeError,应该看上去已经熟悉了。)

例 4.9. 内置属性和内置函数
>>> from apihelper import info
>>> import __builtin__
>>> info(__builtin__, 20)
ArithmeticError      Base class for arithmetic errors.
AssertionError       Assertion failed.
AttributeError       Attribute not found.
EOFError             Read beyond end of file.
EnvironmentError     Base class for I/O related errors.
Exception            Common base class for all exceptions.
FloatingPointError   Floating point operation failed.
IOError              I/O operation failed.

[...snip...]
Python 提供了很多出色的参考手册,你应该好好的精读一下所有 Python 提供的必备模块。对于其它大部分语言,你会发现自己要常常回头参考手册或者 man 页来提醒自己如何使用这些模块,但是 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
46#
 楼主| 发表于 2006-7-15 19:24 | 只看该作者
进一步阅读

使用道具 举报

回复
论坛徽章:
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
47#
 楼主| 发表于 2006-7-15 19:24 | 只看该作者
4.4. 通过 getattr 获取对象引用
4.4.1. 用于模块的 getattr
4.4.2. getattr 作为一个分发者
你已经知道 Python 函数是对象。 你不知道的是,使用 getattr 函数,可以得到一个直到运行时才知道名称的函数的引用。

例 4.10. getattr 介绍
>>> li = ["Larry", "Curly"]
>>> li.pop                       
<built-in method pop of list object at 010DF884>
>>> getattr(li, "pop"           
<built-in method pop of list object at 010DF884>
>>> getattr(li, "append"("Moe"
>>> li
["Larry", "Curly", "Moe"]
>>> getattr({}, "clear"         
<built-in method clear of dictionary object at 00F113D4>
>>> getattr((), "pop"           
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'pop'  该语句获取列表的 pop 方法的引用。注意该语句并不是调用 pop 方法;调用 pop 方法的应该是 li.pop()。这里指的是方法对象本身。
  该语句也是返回 pop 方法的引用,但是此时,方法名称是作为一个字符串参数传递给 getattr 函数的。getattr 是一个有用到令人无法致信的内置函数,可以返回任何对象的任何属性。在这个例子中,对象是一个 list,属性是 pop 方法。
  如果不深信它是多么的有用,试试这个:getattr 的返回值 是 方法,然后你就可以调用它就像直接使用 li.append("Moe" 一样。但是实际上你没有直接调用函数;只是以字符串形式指定了函数名称。
  getattr 也可以作用于字典。
  理论上,getattr 可以作用于元组,但是由于 元组没有方法,所以不管你指定什么属性名称 getattr 都会引发一个异常。

使用道具 举报

回复
论坛徽章:
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
48#
 楼主| 发表于 2006-7-15 19:24 | 只看该作者
4.4.1. 用于模块的 getattr
getattr 不仅仅适用于内置数据类型,也可作用于模块。

例 4.11. apihelper.py 中的 getattr 函数
>>> import odbchelper
>>> odbchelper.buildConnectionString            
<function buildConnectionString at 00D18DD4>
>>> getattr(odbchelper, "buildConnectionString"
<function buildConnectionString at 00D18DD4>
>>> object = odbchelper
>>> method = "buildConnectionString"
>>> getattr(object, method)                     
<function buildConnectionString at 00D18DD4>
>>> type(getattr(object, method))               
<type 'function'>
>>> import types
>>> type(getattr(object, method)) == types.FunctionType
True
>>> callable(getattr(object, method))            
True  该语句返回 odbchelper 模块中 buildConnectionString 函数的引用,第 2 章 第一个 Python 程序 你已经研习过这个方法了。(你看到的这个十六进制地址是我机器上的;你的输出结果会有所不同。)
  使用 getattr,你能够获得同一函数的同一引用。通常,getattr(object, "attribute" 等价于 object.attribute。如果 object 是一个模块的话,那么 attribute 可能是定义在模块中的任何东西:函数、类或者全局变量。
  接下来的是你真正用在 info 函数中的东西。object 作为一个参数传递给函数; method 是方法或者函数的名称字符串。
  在这个例子中,method 是函数的名称,通过获取 type 可以进行验证。
  由于 method 是一个函数,所以它是可调用的。

使用道具 举报

回复
论坛徽章:
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
49#
 楼主| 发表于 2006-7-15 19:25 | 只看该作者
4.4.2. getattr 作为一个分发者
getattr 常见的使用模式是作为一个分发者。举个例子,如果你有一个程序可以以不同的格式输出数据,你可以为每种输出格式定义各自的格式输出函数,然后使用唯一的分发函数调用所需的格式输出函数。

例如,让我们假设有一个以 HTML、XML 和普通文本格式打印站点统计的程序。输出格式在命令行中指定,或者保存在配置文件中。statsout 模块定义了三个函数:output_html、output_xml 和 output_text。然后主程序定义了唯一的输出函数,如下:

例 4.12. 使用getattr 创建分发者

import statsout

def output(data, format="text":                              
    output_function = getattr(statsout, "output_%s" % format)
    return output_function(data)                              
  output 函数接收一个必备参数 data,和一个可选参数 format。如果没有指定 format 参数,其缺省值是 text 并完成普通文本输出函数的调用。
  你可以连接 format 参数值和 "output_" 来创建一个函数名称作为参数值,然后从 statsout 模块中取得该函数。这种方式允许今后很容易的扩展程序以支持其它的输出格式,而且无需修改分发函数。所要做的仅仅是向 statsout 中添加一个函数,比如 output_pdf,之后只要将 “pdf” 作为 format 的参数值传递给 output 函数即可。
  现在你可以简单的调用输出函数就像调用其它函数一样了。output_function 变量是指向 statsout 模块中相应函数的引用。

你是否发现前面示例的一个 Bug?即字符串和函数之间的松耦合,而且没有错误检查。如果用户传入一个格式参数,但是在 statsout 中没有定义相应的格式输出函数,会发生什么呢?还好,getattr 会返回 None,它会取代一个有效函数并被赋值给 output_function,然后下一行调用函数的语句将会失败并抛出一个异常。这种方式不好。

值得庆幸的是,getattr 能够使用可选的第三个参数,一个缺省返回值。

例 4.13. getattr 缺省值

import statsout

def output(data, format="text":
    output_function = getattr(statsout, "output_%s" % format, statsout.output_text)
    return output_function(data)
  这个函数调用一定可以工作,因为你在调用 getattr 时添加了第三个参数。第三个参数是一个缺省返回值,如果第二个参数指定的属性或者方法没能找到,则将返回这个缺省返回值。

正如你所看到,getattr 是相当强大的。它是自省的核心,在后面的章节中你将看到它更强大的示例。

使用道具 举报

回复
论坛徽章:
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
50#
 楼主| 发表于 2006-7-15 19:25 | 只看该作者
4.5. 过滤列表
如你所知,Python 具有通过列表解析(第 3.6 节 “映射 list”)将列表映射到其它列表的强大能力。这种能力同过滤机制结合使用,使列表中的有些元素被映射的同时跳过另外一些元素。

过滤列表语法:

[mapping-expression for element in source-list if filter-expression]这是你所知所爱的 列表解析 的扩展。前三部分都是相同的;最后一部分,以 if 开头的是过滤器表达式。过滤器表达式可以是返回值为真或者假(在 Python 中是 几乎任何东西)的任何表达式。任何经过滤器表达式演算值为元素的真都可以包含在映射中。其它的元素都将忽略,它们不会进入映射表达式,更不会包含在输出列表中。

例 4.14. 列表过滤介绍
>>> li = ["a", "mpilgrim", "foo", "b", "c", "b", "d", "d"]
>>> [elem for elem in li if len(elem) > 1]      
['mpilgrim', 'foo']
>>> [elem for elem in li if elem != "b"]         
['a', 'mpilgrim', 'foo', 'c', 'd', 'd']
>>> [elem for elem in li if li.count(elem) == 1]
['a', 'mpilgrim', 'foo', 'c']  这里的映射表达式很简单(只是返回每个元素的值),所以请把注意力集中到过滤器表达式上。由于 Python 会遍历整个列表,它将对每个元素执行过滤器表达式。如果过滤器表达式演算值为真,该元素就会被映射,同时映射表达式的结果将包含在返回的列表中。这里,你过滤掉了所有单字符的字符串,留下了一个由长字符串构成的列表。
  这里你过滤掉了一个特定值 b。 注意这个过滤器会过滤掉所有的 b,因为每次取出 b,过滤表达式都将为假。
  count 是一个列表方法,返回某个值在列表中出现的次数。你可以认为这个过滤器将从列表中剔除重复元素,返回一个只包含了在原始列表中有着唯一值拷贝的列表。但并非如此,因为在原始列表中出现两次的值(在本例中,b 和 d)被完全剔除了。从一个列表中排除重复值有多种方法,但过滤并不是其中的一种。

回到 apihelper.py 中的这一行:

    methodList = [method for method in dir(object) if callable(getattr(object, method))]这行看上去挺复杂的,确实也很复杂,但是基本结构都还是一样的。整个过滤表达式返回一个列表,并赋值给 methodList 变量。表达式的前半部分是列表映射部分。映射表达式是一个和遍历元素相同的表达式,因此它返回每个元素的值。dir(object) 返回 object 对象的属性和方法列表——你正在映射的列表。所以唯一新出现的部分就是在 if 后面的过滤表达式。

过滤表达式看上去很恐怖,其实不是。你已经知道了 callable、getattr 和 in。正如你在 前面的部分 中看到的,如果 object 是一个模块,并且 method 是上述模块中某个函数的名称,那么表达式 getattr(object, method) 将返回一个函数对象。

所以这个表达式接收一个名为 object 的对象,然后得到它的属性、方法、函数和其他部件的名称列表,接着过滤掉我们不关心的部件。执行过滤行为是通过对每个属性/方法/函数的名称调用 getattr 函数取得实际部件的引用,然后检查这些部件对象是否是可调用的,当然这些可调用的部件对象可能是方法或者函数,同时也可能是内置的(比如列表的 pop 方法)或者用户自定义的(比如 odbchelper 模块的 buildConnectionString 函数)。这里你不用关心其它的属性,如内置在每一个模块中的 __name__ 属性。

使用道具 举报

回复

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

本版积分规则 发表回复

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