成&c nbsp 替换成空格都&c nbsp 替换成空格刻&c nbsp 替换成空格章-主页

EXO:换面天后&&逆袭日记
《EXO:换面天后&&逆袭日记》最新章节
《EXO:换面天后&&逆袭日记》全部章节目录
都市推荐阅读:
《EXO:换面天后&&逆袭日记》所有内容均来自互联网或网友上传,无错小说网只为原作者紫魂妖姬的小说进行宣传。欢迎各位书友支持紫魂妖姬并收藏《EXO:换面天后&&逆袭日记》最新章节。sponsored links
Dive&into&python&第4章&自省的威…
来自:http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/index.html
第四章 自省的威力
本章论述了&Python&众多强大功能之一:自省。正如你所知道的,万物皆对象" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/getting_to_know_python/everything_is_an_object.html">Python&中万物皆对象,自省是指代码可以查看内存中以对象形式存在的其它模块和函数,获取它们的信息,并对它们进行操作。用这种方法,你可以定义没有名称的函数,不按函数声明的参数顺序调用函数,甚至引用事先并不知道名称的函数。
下面是一个完整可运行的&Python&程序。大概看一下这段程序,你应该可以理解不少了。用数字标出的行阐述了&2&章&第一个 Python 程序" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/getting_to_know_python/index.html">第&2&章&第一个
程序&中涉及的一些概念。如果剩下来的代码看起来有点奇怪,不用担心,通过阅读本章你将会理解所有这些。
例&4.1.&apihelper.py
如果您还没有下载本书附带的样例程序, 可以&下载本程序和其他样例程序。
def info(object, spacing=10, collapse=1): into&python&第4章&自省的威力" /> into&python&第4章&自省的威力" /> into&python&第4章&自省的威力" />
"""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__":
into&python&第4章&自省的威力" /> into&python&第4章&自省的威力" />
print info.__doc__
into&python&第4章&自省的威力" />
该模块有一个声明为&info&的函数。根据它的函数声明" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/getting_to_know_python/declaring_functions.html">函数声明可知,它有三个参数:&object、spacing&和&collapse。实际上后面两个参数都是可选参数,关于这点你很快就会看到。
into&python&第4章&自省的威力" />
info&函数有一个多行的&文档化函数" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/getting_to_know_python/documenting_functions.html">doc
string,简要地描述了函数的功能。注意这里并没有提到返回值;单独使用这个函数只是为了这个函数产生的效果,并不是为了它的返回值。
into&python&第4章&自省的威力" />
函数内的代码是代码缩进" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/getting_to_know_python/indenting_code.html">缩进形式的。
into&python&第4章&自省的威力" />
if&__name__&技巧允许这个程序在自己独立运行时做些有用的事情,同时又不妨碍作为其它程序的模块使用。在这个例子中,程序只是简单地打印出&info&函数的&doc
into&python&第4章&自省的威力" />
if&语句使用&==&进行比较,而且不需要括号。
info&函数的设计意图是提供给工作在&Python&IDE&中的开发人员使用,它可以接受任何含有函数或者方法的对象
(比如模块,含有函数,又比如list,含有方法)
作为参数,并打印出对象的所有函数和它们的&doc
例&4.2.&apihelper.py&的用法示例
&&& from apihelper import info
&&& li = []
&&& info(li)
L.append(object) -- append object to end
L.count(value) -& integer -- return number of occurrences of value
L.extend(list) -- extend list by appending list elements
L.index(value) -& integer -- return index of first occurrence of value
L.insert(index, object) -- insert object before index
L.pop([index]) -& item -- remove and return item at index (default last)
L.remove(value) -- remove first occurrence of value
L.reverse() -- reverse *IN PLACE*
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.
into&python&第4章&自省的威力"
TITLE="Dive&into&python&第4章&自省的威力" />
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)
into&python&第4章&自省的威力" />
info(odbchelper, 12)
into&python&第4章&自省的威力" />
info(odbchelper, collapse=0)
into&python&第4章&自省的威力" />
info(spacing=15, object=odbchelper) into&python&第4章&自省的威力" />
into&python&第4章&自省的威力" />
只使用一个参数,spacing&使用缺省值&10&,collapse&使用缺省值&1。
into&python&第4章&自省的威力" />
使用两个参数,collapse&使用缺省值&1。
into&python&第4章&自省的威力" />
这里你显式命名了&collapse&并指定了它的值。spacing&将依然使用它的缺省值&10。
into&python&第4章&自省的威力" />
甚至必备参数
(例如&object,没有指定缺省值)
也可以采用命名参数的方式,而且命名参数可以以任意顺序出现。
这些看上去非常累,除非你意识到参数不过是一个字典。“通常”
不使用参数名称的函数调用只是一个简写的形式,Python&按照函数声明中定义的的参数顺序将参数值和参数名称匹配起来。大部分时间,你会使用“通常”方式调用函数,但是如果你需要,总是可以提供附加的灵活性。
调用函数时唯一必须做的事情就是为每一个必备参数指定值 (以某种方式);以何种具体的方式和顺序都取决于你。
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&模块中列出了可能的数据类型。这对于处理多种数据类型的帮助者函数&[1]&非常有用。
例&4.5.&type&介绍
&&& type(1)
into&python&第4章&自省的威力" />
&type 'int'&
&&& li = []
&&& type(li)
into&python&第4章&自省的威力" />
&type 'list'&
&&& import odbchelper
&&& type(odbchelper)
into&python&第4章&自省的威力" />
&type 'module'&
&&& import types
into&python&第4章&自省的威力" />
&&& type(odbchelper) == types.ModuleType
into&python&第4章&自省的威力" />
type&可以接收任何东西作为参数――我的意思是任何东西――并返回它的数据类型。整型、字符串、列表、字典、元组、函数、类、模块,甚至类型对象都可以作为参数被&type&函数接受。
into&python&第4章&自省的威力" />
type&可以接收变量作为参数,并返回它的数据类型。
into&python&第4章&自省的威力" />
type&还可以作用于模块。
into&python&第4章&自省的威力" />
你可以使用&types&模块中的常量来进行对象类型的比较。这就是&info&函数所做的,很快你就会看到。
4.3.2.&str&函数
str&将数据强制转换为字符串。每种数据类型都可以强制转换为字符串。
例&4.6.&str&介绍
&&& str(1)
into&python&第4章&自省的威力" />
&&& horsemen = ['war', 'pestilence', 'famine']
&&& horsemen
['war', 'pestilence', 'famine']
&&& horsemen.append('Powerbuilder')
&&& str(horsemen)
into&python&第4章&自省的威力" />
"['war', 'pestilence', 'famine', 'Powerbuilder']"
&&& str(odbchelper) into&python&第4章&自省的威力" />
"&module 'odbchelper' from 'c:\\docbook\\dip\\py\\odbchelper.py'&"
&&& str(None)
into&python&第4章&自省的威力" />
into&python&第4章&自省的威力" />
对于简单的数据类型比如整型,你可以预料到&str&的正常工作,因为几乎每种语言都有一个将整型转化为字符串的函数。
into&python&第4章&自省的威力" />
然而&str&可以作用于任何数据类型的任何对象。这里它作用于一个零碎构建的列表。
into&python&第4章&自省的威力" />
str&还允许作用于模块。注意模块的字符串形式表示包含了模块在磁盘上的路径名,所以你的显示结果将会有所不同。
into&python&第4章&自省的威力" />
str&的一个细小但重要的行为是它可以作用于&None,None&是&Python&的
值。这个调用返回字符串&'None'。你将会使用这一点来改进你的&info&函数,这一点你很快就会看到。
info&函数的核心是强大的&dir&函数。dir&函数返回任意对象的属性和方法列表,包括模块对象、函数对象、字符串对象、列表对象、字典对象
…… 相当多的东西。
into&python&第4章&自省的威力"
TITLE="Dive&into&python&第4章&自省的威力" />
例&4.7.&dir&介绍
&&& li = []
&&& dir(li)
into&python&第4章&自省的威力" />
['append', 'count', 'extend', 'index', 'insert',
'pop', 'remove', 'reverse', 'sort']
&&& d = {}
&&& dir(d)
into&python&第4章&自省的威力" />
['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'setdefault', 'update', 'values']
&&& import odbchelper
&&& dir(odbchelper)
into&python&第4章&自省的威力" />
['__builtins__', '__doc__', '__file__', '__name__', 'buildConnectionString']
into&python&第4章&自省的威力" />
li&是一个列表,所以&dir(li)&返回一个包含所有列表方法的列表。注意返回的列表只包含了字符串形式的方法名称,而不是方法对象本身。
into&python&第4章&自省的威力" />
d&是一个字典,所以&dir(d)&返回字典方法的名称列表。其中至少有一个方法,3.25.&keys, values 和 items 函数" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/native_data_types/mapping_lists.html#odbchelper.items">keys,看起来还是挺熟悉的。
into&python&第4章&自省的威力" />
这里就是真正变得有趣的地方。odbchelper&是一个模块,所以&dir(odbchelper)&返回模块中定义的所有部件的列表,包括内置的属性,例如&__name__、2.3.&访问 buildConnectionString 函数的 doc string" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/getting_to_know_python/everything_is_an_object.html#odbchelper.import">__doc__,以及其它你所定义的属性和方法。在这个例子中,odbchelper&只有一个用户定义的方法,就是在第
章中论述的&buildConnectionString&函数。
最后是&callable&函数,它接收任何对象作为参数,如果参数对象是可调用的,返回&True;否则返回&False。可调用对象包括函数、类方法,甚至类自身
(下一章将更多的关注类)。
例&4.8.&callable&介绍
&&& import string
&&& string.punctuation
into&python&第4章&自省的威力" />
'!"#$%&\'()*+,-./:;&=&?@[\\]^_`{|}~'
&&& string.join
into&python&第4章&自省的威力" />
&function join at 00C55A7C&
&&& callable(string.punctuation) into&python&第4章&自省的威力" />
&&& callable(string.join)
into&python&第4章&自省的威力" />
&&& print string.join.__doc__
into&python&第4章&自省的威力" />
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)
into&python&第4章&自省的威力" />
string&模块中的函数现在已经不赞成使用了
(尽管很多人现在仍然还在使用&join&函数),但是在这个模块中包含了许多有用的变量,例如&string.punctuation,这个字符串包含了所有标准的标点符号字符。
into&python&第4章&自省的威力" />
连接 list 与分割字符串" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/native_data_types/joining_lists.html">
string.join&是一个用于连接字符串列表的函数。
into&python&第4章&自省的威力" />
string.punctuation&是不可调用的对象;它是一个字符串。(字符串确有可调用的方法,但是字符串本身不是可调用的。)
into&python&第4章&自省的威力" />
string.join&是可调用的;这个函数可以接受两个参数。
into&python&第4章&自省的威力" />
任何可调用的对象都有&doc
string。通过将&callable&函数作用于一个对象的每个属性,可以确定哪些属性
(方法、函数、类) 是你要关注的,哪些属性 (常量等等) 是你可以忽略、之前不需要知道的。
4.3.3.&内置函数
type、str、dir&和其它的&Python&内置函数都归组到了&__builtin__&(前后分别是双下划线)
这个特殊的模块中。如果有帮助的话,你可以认为&Python&在启动时自动执行了from
__builtin__ import *,此语句将所有的 “内置”
函数导入该命名空间,所以在这个命名空间中可以直接使用这些内置函数。
像这样考虑的好处是,你是可以获取&__builtin__&模块信息的,并以组的形式访问所有的内置函数和属性。猜到什么了吗,现在我们的&Python&有一个称为&info&的函数。自己尝试一下,略看一下结果列表。后面我们将深入到一些更重要的函数。(一些内置的错误类,比如&3.16.&Tuple 没有方法" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/native_data_types/tuples.html#odbchelper.tuplemethods">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.
Read beyond end of file.
EnvironmentError
Base class for I/O related errors.
Common base class for all exceptions.
FloatingPointError
Floating point operation failed.
I/O operation failed.
[...snip...]
Python&提供了很多出色的参考手册,你应该好好地精读一下所有&Python&提供的必备模块。对于其它大部分语言,你会发现自己要常常回头参考手册或者
页来提醒自己如何使用这些模块,但是&Python&不同于此,它很大程度上是自文档化的。
4.4.&通过&getattr&获取对象引用
4.4.1. 用于模块的 getattr
4.4.2. getattr 作为一个分发者
你已经知道&万物皆对象" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/getting_to_know_python/everything_is_an_object.html">Python&函数是对象。你不知道的是,使用&getattr&函数,可以得到一个直到运行时才知道名称的函数的引用。
例&4.10.&getattr&介绍
&&& li = ["Larry", "Curly"]
&&& li.pop
into&python&第4章&自省的威力" />
&built-in method pop of list object at 010DF884&
&&& getattr(li, "pop")
into&python&第4章&自省的威力" />
&built-in method pop of list object at 010DF884&
&&& getattr(li, "append")("Moe") into&python&第4章&自省的威力" />
["Larry", "Curly", "Moe"]
&&& getattr({}, "clear")
into&python&第4章&自省的威力" />
&built-in method clear of dictionary object at 00F113D4&
&&& getattr((), "pop")
into&python&第4章&自省的威力" />
Traceback (innermost last):
File "&interactive input&", line 1, in ?
AttributeError: 'tuple' object has no attribute 'pop'
into&python&第4章&自省的威力" />
该语句获取列表的&pop&方法的引用。注意该语句并不是调用&pop&方法;调用&pop&方法的应该是&li.pop()。这里指的是方法对象本身。
into&python&第4章&自省的威力" />
该语句也是返回&pop&方法的引用,但是此时,方法名称是作为一个字符串参数传递给&getattr&函数的。getattr&是一个有用到令人无法致信的内置函数,可以返回任何对象的任何属性。在这个例子中,对象是一个
list,属性是&pop&方法。
into&python&第4章&自省的威力" />
如果不确信它是多么的有用,试试这个:getattr&的返回值是&方法,然后你就可以调用它,就像直接使用&li.append("Moe")&一样。但是实际上你没有直接调用函数;只是以字符串形式指定了函数名称。
into&python&第4章&自省的威力" />
getattr&也可以作用于字典。
into&python&第4章&自省的威力" />
理论上,getattr&可以作用于元组,但是由于3.16.&Tuple 没有方法" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/native_data_types/tuples.html#odbchelper.tuplemethods">元组没有方法,所以不管你指定什么属性名称&getattr&都会引发一个异常。
4.4.1.&用于模块的&getattr
getattr&不仅仅适用于内置数据类型,也可作用于模块。
例&4.11.&apihelper.py&中的&getattr&函数
&&& import odbchelper
&&& odbchelper.buildConnectionString
into&python&第4章&自省的威力" />
&function buildConnectionString at 00D18DD4&
&&& getattr(odbchelper, "buildConnectionString") into&python&第4章&自省的威力" />
&function buildConnectionString at 00D18DD4&
&&& object = odbchelper
&&& method = "buildConnectionString"
&&& getattr(object, method)
into&python&第4章&自省的威力" />
&function buildConnectionString at 00D18DD4&
&&& type(getattr(object, method))
into&python&第4章&自省的威力" />
&type 'function'&
&&& import types
&&& type(getattr(object, method)) == types.FunctionType
&&& callable(getattr(object, method))
into&python&第4章&自省的威力" />
into&python&第4章&自省的威力" />
该语句返回&odbchelper&模块中&buildConnectionString&函数的引用,2&章&第一个 Python 程序" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/getting_to_know_python/index.html">第&2&章&第一个
程序&你已经研习过这个方法了。(你看到的这个十六进制地址是我机器上的;你的输出结果会有所不同。)
into&python&第4章&自省的威力" />
使用&getattr,你能够获得同一函数的同一引用。通常,getattr(object,
"attribute")&等价于&object.attribute。如果&object&是一个模块的话,那么&attribute&可能是定义在模块中的任何东西:函数、类或者全局变量。
into&python&第4章&自省的威力" />
接下来的是你真正用在&info&函数中的东西。object&作为一个参数传递给函数;&method&是方法或者函数的名称字符串。
into&python&第4章&自省的威力" />
在这个例子中,method&是函数的名称,通过获取&4.5.&type 介绍" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/built_in_functions.html#apihelper.type.intro">type&可以进行验证。
into&python&第4章&自省的威力" />
由于&method&是一个函数,所以它是4.8.&callable 介绍" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/built_in_functions.html#apihelper.builtin.callable">可调用的。
4.4.2.&getattr&作为一个分发者
getattr&常见的使用模式是作为一个分发者。举个例子,如果你有一个程序可以以不同的格式输出数据,你可以为每种输出格式定义各自的格式输出函数,然后使用唯一的分发函数调用所需的格式输出函数。
例如,让我们假设有一个以&HTML、XML&和普通文本格式打印站点统计的程序。输出格式在命令行中指定,或者保存在配置文件中。statsout&模块定义了三个函数:output_html、output_xml&和&output_text。然后主程序定义了唯一的输出函数,如下:
例&4.12.&使用getattr&创建分发者
import statsout
def output(data, format="text"):
into&python&第4章&自省的威力" />
output_function = getattr(statsout, "output_%s" % format) into&python&第4章&自省的威力" />
return output_function(data)
into&python&第4章&自省的威力" />
into&python&第4章&自省的威力" />
output&函数接收一个必备参数&data,和一个可选参数&format。如果没有指定&format&参数,其缺省值是&text&并完成普通文本输出函数的调用。
into&python&第4章&自省的威力" />
你可以连接&format&参数值和
来创建一个函数名称作为参数值,然后从&statsout&模块中取得该函数。这种方式允许今后很容易地扩展程序以支持其它的输出格式,而且无需修改分发函数。所要做的仅仅是向&statsout&中添加一个函数,比如&output_pdf,之后只要将
作为&format&的参数值传递给&output&函数即可。
into&python&第4章&自省的威力" />
现在你可以简单地调用输出函数,就像调用其它函数一样。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) into&python&第4章&自省的威力" />
into&python&第4章&自省的威力" />
这个函数调用一定可以工作,因为你在调用&getattr&时添加了第三个参数。第三个参数是一个缺省返回值,如果第二个参数指定的属性或者方法没能找到,则将返回这个缺省返回值。
正如你所看到,getattr&是相当强大的。它是自省的核心,在后面的章节中你将看到它更强大的示例。
4.5.&过滤列表
如你所知,Python&具有通过列表解析
(映射 list" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/native_data_types/mapping_lists.html">第&3.6&节
“映射 list”)
将列表映射到其它列表的强大能力。这种能力同过滤机制结合使用,使列表中的有些元素被映射的同时跳过另外一些元素。
过滤列表语法:
[mapping-expression for element in source-list if filter-expression]
这是你所知所爱的映射 list" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/native_data_types/mapping_lists.html">列表解析的扩展。前三部分都是相同的;最后一部分,以&if&开头的是过滤器表达式。过滤器表达式可以是返回值为真或者假的任何表达式
(在&Python中是几乎任何东西)。任何经过滤器表达式演算值为真的元素都可以包含在映射中。其它的元素都将忽略,它们不会进入映射表达式,更不会包含在输出列表中。
例&4.14.&列表过滤介绍
&&& li = ["a", "mpilgrim", "foo", "b", "c", "b", "d", "d"]
&&& [elem for elem in li if len(elem) & 1]
into&python&第4章&自省的威力" />
['mpilgrim', 'foo']
&&& [elem for elem in li if elem != "b"]
into&python&第4章&自省的威力" />
['a', 'mpilgrim', 'foo', 'c', 'd', 'd']
&&& [elem for elem in li if li.count(elem) == 1] into&python&第4章&自省的威力" />
['a', 'mpilgrim', 'foo', 'c']
into&python&第4章&自省的威力" />
这里的映射表达式很简单
(只是返回每个元素的值),所以请把注意力集中到过滤器表达式上。由于&Python&会遍历整个列表,它将对每个元素执行过滤器表达式。如果过滤器表达式演算值为真,该元素就会被映射,同时映射表达式的结果将包含在返回的列表中。这里,你过滤掉了所有单字符的字符串,留下了一个由长字符串构成的列表。
into&python&第4章&自省的威力" />
这里你过滤掉了一个特定值&b。注意这个过滤器会过滤掉所有的&b,因为每次取出&b,过滤表达式都将为假。
into&python&第4章&自省的威力" />
count&是一个列表方法,返回某个值在列表中出现的次数。你可以认为这个过滤器将从列表中剔除重复元素,返回一个只包含了在原始列表中有着唯一值拷贝的列表。但并非如此,因为在原始列表中出现两次的值
(在本例中,b&和&d)
被完全剔除了。从一个列表中排除重复值有多种方法,但过滤并不是其中的一种。
回到&apihelper.py&中的这一行:
methodList = [method for method in dir(object) if callable(getattr(object, method))]
这行看上去挺复杂――确实也很复杂――但是基本结构都还是一样的。整个过滤表达式返回一个列表,并赋值给&methodList&变量。表达式的前半部分是列表映射部分。映射表达式是一个和遍历元素相同的表达式,因此它返回每个元素的值。dir(object)&返回&object&对象的属性和方法列表――你正在映射的列表。所以唯一新出现的部分就是在&if后面的过滤表达式。
过滤表达式看上去很恐怖,其实不是。你已经知道了&4.8.&callable 介绍" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/built_in_functions.html#apihelper.builtin.callable">callable、4.10.&getattr 介绍" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/getattr.html#apihelper.getattr.intro">getattr&和&3.16.&Tuple 没有方法" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/native_data_types/tuples.html#odbchelper.tuplemethods">in。正如你在通过 getattr 获取对象引用" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/getattr.html">前面的部分中看到的,如果&object&是一个模块,并且&method&是上述模块中某个函数的名称,那么表达式&getattr(object,
method)&将返回一个函数对象。
所以这个表达式接收一个名为&object&的对象,然后得到它的属性、方法、函数和其他成员的名称列表,接着过滤掉我们不关心的成员。执行过滤行为是通过对每个属性/方法/函数的名称调用&getattr&函数取得实际成员的引用,然后检查这些成员对象是否是可调用的,当然这些可调用的成员对象可能是方法或者函数,同时也可能是内置的
(比如列表的&pop&方法) 或者用户自定义的
(比如&odbchelper&模块的&buildConnectionString&函数)。这里你不用关心其它的属性,如内置在每一个模块中的&__name__&属性。
4.6.&and&和&or&的特殊性质
4.6.1. 使用 and-or 技巧
在Python&中,and&和&or&执行布尔逻辑演算,如你所期待的一样。但是它们并不返回布尔值,而是返回它们实际进行比较的值之一。
例&4.15.&and&介绍
&&& 'a' and 'b'
into&python&第4章&自省的威力" />
&&& '' and 'b'
into&python&第4章&自省的威力" />
&&& 'a' and 'b' and 'c' into&python&第4章&自省的威力" />
into&python&第4章&自省的威力" />
使用&and&时,在布尔环境中从左到右演算表达式的值。0、''、[]、()、{}、None&在布尔环境中为假;其它任何东西都为真。还好,几乎是所有东西。默认情况下,布尔环境中的类实例为真,但是你可以在类中定义特定的方法使得类实例的演算值为假。你将会在第
章中了解到类和这些特殊方法。如果布尔环境中的所有值都为真,那么&and&返回最后一个值。在这个例子中,and&演算&'a'&的值为真,然后是&'b'&的演算值为真,最终返回&'b'。
into&python&第4章&自省的威力" />
如果布尔环境中的某个值为假,则&and&返回第一个假值。在这个例子中,''&是第一个假值。
into&python&第4章&自省的威力" />
所有值都为真,所以&and&返回最后一个真值,'c'。
例&4.16.&or&介绍
&&& 'a' or 'b'
into&python&第4章&自省的威力" />
&&& '' or 'b'
into&python&第4章&自省的威力" />
&&& '' or [] or {}
into&python&第4章&自省的威力" />
&&& def sidefx():
print "in sidefx()"
&&& 'a' or sidefx()
into&python&第4章&自省的威力" />
into&python&第4章&自省的威力" />
使用&or&时,在布尔环境中从左到右演算值,就像&and&一样。如果有一个值为真,or&立刻返回该值。本例中,'a'&是第一个真值。
into&python&第4章&自省的威力" />
or&演算&''&的值为假,然后演算&'b'&的值为真,于是返回&'b'&。
into&python&第4章&自省的威力" />
如果所有的值都为假,or&返回最后一个假值。or&演算&''&的值为假,然后演算&[]&的值为假,依次演算&{}&的值为假,最终返回&{}&。
into&python&第4章&自省的威力" />
注意&or&在布尔环境中会一直进行表达式演算直到找到第一个真值,然后就会忽略剩余的比较值。如果某些值具有副作用,这种特性就非常重要了。在这里,函数sidefx&永远都不会被调用,因为&or&演算&'a'&的值为真,所以紧接着就立刻返回&'a'&了。
如果你是一名&C&语言黑客,肯定很熟悉&bool&?&a&:&b&表达式,如果&bool&为真,表达式演算值为&a,否则为&b。基于&Python&中&and&和&or&的工作方式,你可以完成相同的事情。
4.6.1.&使用&and-or&技巧
例&4.17.&and-or&技巧介绍
&&& a = "first"
&&& b = "second"
&&& 1 and a or b into&python&第4章&自省的威力" />
&&& 0 and a or b into&python&第4章&自省的威力" />
into&python&第4章&自省的威力" />
这个语法看起来类似于&C&语言中的&bool&?&a&:&b&表达式。整个表达式从左到右进行演算,所以先进行&and&表达式的演算。1
'first'&演算值为&'first',然后'first'
'second'&的演算值为&'first'。
into&python&第4章&自省的威力" />
'first'&演算值为&False,然后&0
'second'&演算值为&'second'。
然而,由于这种&Python&表达式单单只是进行布尔逻辑运算,并不是语言的特定构成,这是&and-or&技巧和&C&语言中的&bool&?&a&:&b&语法非常重要的不同。如果&a&为假,表达式就不会按你期望的那样工作了。(你能知道我被这个问题折腾过吗?不止一次?)
例&4.18.&and-or&技巧无效的场合
&&& a = ""
&&& b = "second"
&&& 1 and a or b
into&python&第4章&自省的威力" />
into&python&第4章&自省的威力" />
由于&a&是一个空字符串,在&Python&的布尔环境中空字符串被认为是假的,1
''&的演算值为&'',最后&''
'second'&的演算值为&'second'。噢!这个值并不是你想要的。
and-or&技巧,也就是&bool&and&a&or&b&表达式,当&a&在布尔环境中的值为假时,不会像&C&语言表达式&bool&?&a&:&b&那样工作。
在&and-or&技巧后面真正的技巧是,确保&a&的值决不会为假。最常用的方式是使&a&成为&[a]&、&b&成为&[b],然后使用返回值列表的第一个元素,应该是&a&或&b中的某一个。
例&4.19.&安全使用&and-or&技巧
&&& a = ""
&&& b = "second"
&&& (1 and [a] or [b])[0] into&python&第4章&自省的威力" />
into&python&第4章&自省的威力" />
由于&[a]&是一个非空列表,所以它决不会为假。即使&a&是&0&或者&''&或者其它假值,列表&[a]&也为真,因为它有一个元素。
到现在为止,这个技巧可能看上去问题超过了它的价值。毕竟,使用&if&语句可以完成相同的事情,那为什么要经历这些麻烦事呢?哦,在很多情况下,你要在两个常量值中进行选择,由于你知道&a&的值总是为真,所以你可以使用这种较为简单的语法而且不用担心。对于使用更为复杂的安全形式,依然有很好的理由要求这样做。例如,在Python&语言的某些情况下&if&语句是不允许使用的,比如在&lambda&函数中。
4.7.&使用&lambda&函数
4.7.1. 真实世界中的 lambda 函数
Python&支持一种有趣的语法,它允许你快速定义单行的最小函数。这些叫做&lambda&的函数,是从&Lisp&借用来的,可以用在任何需要函数的地方。
例&4.20.&lambda&函数介绍
&&& def f(x):
return x*2
&&& g = lambda x: x*2
into&python&第4章&自省的威力" />
&&& (lambda x: x*2)(3) into&python&第4章&自省的威力" />
into&python&第4章&自省的威力" />
这是一个&lambda&函数,完成同上面普通函数相同的事情。注意这里的简短的语法:在参数列表周围没有括号,而且忽略了&return&关键字
(隐含存在,因为整个函数只有一行)。而且,该函数没有函数名称,但是可以将它赋值给一个变量进行调用。
into&python&第4章&自省的威力" />
使用&lambda&函数时甚至不需要将它赋值给一个变量。这可能不是世上最有用的东西,它只是展示了&lambda&函数只是一个内联函数。
总的来说,lambda&函数可以接收任意多个参数
(包括使用可选参数和命名参数" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/optional_arguments.html">可选参数)
并且返回单个表达式的值。lambda&函数不能包含命令,包含的表达式不能超过一个。不要试图向&lambda&函数中塞入太多的东西;如果你需要更复杂的东西,应该定义一个普通函数,然后想让它多长就多长。
lambda&函数是一种风格问题。不一定非要使用它们;任何能够使用它们的地方,都可以定义一个单独的普通函数来进行替换。我将它们用在需要封装特殊的、非重用代码上,避免令我的代码充斥着大量单行函数。
4.7.1.&真实世界中的&lambda&函数
apihelper.py&中的&lambda&函数:
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
注意这里使用了&and 和 or 的特殊性质" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/and_or.html">and-or&技巧的简单形式,它是没问题的,因为&lambda&函数在布尔环境中总是为真。(这并不意味这&lambda&函数不能返回假值。这个函数对象的布尔值为真;它的返回值可以是任何东西。)
还要注意的是使用了没有参数的&split&函数。你已经看到过它带3.28.&分割字符串" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/native_data_types/joining_lists.html#odbchelper.split.example">一个或者两个参数的使用,但是不带参数它按空白进行分割。
例&4.21.&split&不带参数
&&& s = "this
is\na\ttest"
into&python&第4章&自省的威力" />
&&& print s
&&& print s.split()
into&python&第4章&自省的威力" />
['this', 'is', 'a', 'test']
&&& print " ".join(s.split()) into&python&第4章&自省的威力" />
'this is a test'
into&python&第4章&自省的威力" />
这是一个多行字符串,通过使用转义字符的定义代替了2.2.&定义 buildConnectionString 函数的 doc string" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/getting_to_know_python/documenting_functions.html#odbchelper.triplequotes">三重引号。\n&是一个回车,\t&是一个制表符。
into&python&第4章&自省的威力" />
不带参数的&split&按照空白进行分割。所以三个空格、一个回车和一个制表符都是一样的。
into&python&第4章&自省的威力" />
通过&split&分割字符串你可以将空格统一化;然后再以单个空格作为分隔符用&join&将其重新连接起来。这也就是&info&函数将多行&doc
string&合并成单行所做的事情。
那么&info&函数到底用这些&lambda&函数、split&函数和&and-or&技巧做了些什么呢?
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
processFunc&现在是一个函数,但是它到底是哪一个函数还要取决于&collapse&变量。如果&collapse&为真,processFunc(string)&将压缩空白;否则&processFunc(string)&将返回未改变的参数。
在一个不很健壮的语言中实现它,像&Visual
Basic,你很有可能要创建一个函数,接受一个字符串参数和一个&collapse&参数,并使用&if&语句确定是否压缩空白,然后再返回相应的值。这种方式是低效的,因为函数可能需要处理每一种可能的情况。每次你调用它,它将不得不在给出你所想要的东西之前,判断是否要压缩空白。在&Python中,你可以将决策逻辑拿到函数外面,而定义一个裁减过的&lambda&函数提供确切的
(唯一的) 你想要的。这种方式更为高效、更为优雅,而且很少引起那些令人讨厌 (哦,想到那些参数就头昏) 的错误。
4.8.&全部放在一起
最后一行代码是唯一还没有解释过的,它完成全部的工作。但是现在工作已经简单了,因为所需要的每件事都已经按照需求建立好了。所有的多米诺骨牌已经就位,到了将它们推倒的时候了。
下面是&apihelper.py&的关键
print "\n".join(["%s %s" %
(method.ljust(spacing),
processFunc(str(getattr(object, method).__doc__)))
for method in methodList])
注意这是一条命令,被分隔成了多行,但是并没有使用续行符 (\)。还记得我说过一些表达式可以分割成多行而不需要使用反斜线吗?列表解析就是这些表达式之一,因为整个表达式包括在方括号里。
现在,让我们从后向前分析。
for method in methodList
告诉我们这是一个映射 list" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/native_data_types/mapping_lists.html">列表解析。如你所知&methodList&是&object&中所有你关心的方法的一个列表。所以你正在使用&method&遍历列表。
例&4.22.&动态得到&doc string
&&& import odbchelper
&&& object = odbchelper
into&python&第4章&自省的威力" />
&&& method = 'buildConnectionString'
into&python&第4章&自省的威力" />
&&& getattr(object, method)
into&python&第4章&自省的威力" />
&function buildConnectionString at 010D6D74&
&&& print getattr(object, method).__doc__ into&python&第4章&自省的威力" />
Build a connection string from a dictionary of parameters.
Returns string.
into&python&第4章&自省的威力" />
在&info&函数中,object&是要得到帮助的对象,作为一个参数传入。
into&python&第4章&自省的威力" />
在你遍历&methodList&时,method&是当前方法的名称。
into&python&第4章&自省的威力" />
通过&通过 getattr 获取对象引用" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/getattr.html">getattr&函数,你可以得到&object&模块中&method&函数的引用。
into&python&第4章&自省的威力" />
现在,很容易就可以打印出方法的&doc
接下来令人困惑的是&doc
string&周围&str&的使用。你可能记得,str&是一个内置函数,它可以使用 type、str、dir 和其它内置函数" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/built_in_functions.html">强制将数据转化为字符串。但是一个&doc
string&应该总是一个字符串,为什么还要费事地使用&str&函数呢?答案就是:不是每个函数都有&doc
string&,如果没有,这个&__doc__&属性为&None。
例&4.23.&为什么对一个&doc
string&使用&str&?
&&& &&& def foo(): print 2
&&& &&& foo()
&&& &&& foo.__doc__
into&python&第4章&自省的威力" />
&&& foo.__doc__ == None into&python&第4章&自省的威力" />
&&& str(foo.__doc__)
into&python&第4章&自省的威力" />
into&python&第4章&自省的威力" />
你可以很容易的定义一个没有&doc
string&的函数,这种情况下它的&__doc__&属性为&None。令人迷惑的是,如果你直接演算&__doc__&属性的值,Python&IDE&什么都不会打印。这是有意义的
(前提是你考虑了这个结果的来由),但是却没有什么用。
into&python&第4章&自省的威力" />
你可以直接通过&__doc__&属性和&None&的比较验证&__doc__&属性的值。
into&python&第4章&自省的威力" />
str&函数可以接收值为 null
的参数,然后返回它的字符串表示,'None'。
在&SQL&中,你必须使用&IS
NULL&代替&=
NULL&进行 null
值比较。在&Python,你可以使用&==
None&或者&is
None&进行比较,但是&is
None&更快。
现在你确保有了一个字符串,可以把这个字符串传给&processFunc,这个函数使用 lambda 函数" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/lambda_functions.html">已经定义是一个既可以压缩空白也可以不压缩空白的函数。现在你看出来为什么使用&str&将&None转化为一个字符串很重要了。processFunc&假设接收到一个字符串参数然后调用&split&方法,如果你传入&None&,将导致程序崩溃,因为&None&没有&split&方法。
再往回走一步,你再一次使用了字符串格式化来连接&processFunc&的返回值
和&method&的&ljust&方法的返回值。ljust&是一个你之前没有见过的新字符串方法。
例&4.24.&ljust&方法介绍
&&& s = 'buildConnectionString'
&&& s.ljust(30) into&python&第4章&自省的威力" />
'buildConnectionString
&&& s.ljust(20) into&python&第4章&自省的威力" />
'buildConnectionString'
into&python&第4章&自省的威力" />
ljust&用空格填充字符串以符合指定的长度。info&函数使用它生成了两列输出并将所有在第二列的&doc
string&纵向对齐。
into&python&第4章&自省的威力" />
如果指定的长度小于字符串的长度,ljust&将简单地返回未变化的字符串。它决不会截断字符串。
几乎已经完成了。有了&ljust&方法填充过的方法名称和来自调用&processFunc&方法得到的&doc
string&(可能压缩过),你就可以将两者连接起来并得到单个字符串。因为对methodList&进行了映射,最终你将获得一个字符串列表。利用&"\n"&的&join&函数,将这个列表连接为单个字符串,列表中每个元素独占一行,接着打印出结果。
例&4.25.&打印列表
&&& li = ['a', 'b', 'c']
&&& print "\n".join(li) into&python&第4章&自省的威力" />
into&python&第4章&自省的威力" />
在你处理列表时,这确实是一个有用的调试技巧。在&Python&中,你会十分频繁地操作列表。
上述就是最后一个令人困惑的地方了。但是现在你应该已经理解这段代码了。
print "\n".join(["%s %s" %
(method.ljust(spacing),
processFunc(str(getattr(object, method).__doc__)))
for method in methodList])
into&python&第4章&自省的威力"
TITLE="Dive&into&python&第4章&自省的威力" />
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__
apihelper.py&的输出:
&&& from apihelper import info
&&& li = []
&&& info(li)
L.append(object) -- append object to end
L.count(value) -& integer -- return number of occurrences of value
L.extend(list) -- extend list by appending list elements
L.index(value) -& integer -- return index of first occurrence of value
L.insert(index, object) -- insert object before index
L.pop([index]) -& item -- remove and return item at index (default last)
L.remove(value) -- remove first occurrence of value
L.reverse() -- reverse *IN PLACE*
L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -& -1, 0, 1
在研究下一章前,确保你可以无困难的完成下面这些事情:
用使用可选参数和命名参数" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/optional_arguments.html">可选和命名参数定义和调用函数
用&4.6.&str 介绍" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/built_in_functions.html#apihelper.str.intro">str&强制转换任意值为字符串形式
用&通过 getattr 获取对象引用" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/getattr.html">getattr&动态得到函数和其它属性的引用
扩展列表解析语法实现过滤列表" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/filtering_lists.html">列表过滤
识别&and 和 or 的特殊性质" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/and_or.html">and-or&技巧并安全地使用它
定义&使用 lambda 函数" HREF="http://www.kuqin.com/docs/diveintopythonzh-cn-5.4b/html/power_of_introspection/lambda_functions.html">lambda&函数
将函数赋值给变量然后通过引用变量调用函数。我强调的已经够多了:这种思考方式对于提高对&Python&的理解力至关重要。在本书中你会随处可见这种技术的更复杂的应用。
简明 Python 教程 第4章 基本概念 上一页 缩进 下一页 缩进 空白在Python中是重要的.事实上行首的空白是重要的.它称为缩进.在逻辑行首的空白(空格和制表符)用来决定逻辑行的缩进层次,从而用来决定语句的分组. 这意味着同一层次的语句必须有相同的缩进.每一组这样的语句称为一个块.我们将在后面的章节中看到有关块的用处的例子. 你需要记住的一样东西是 ...
简明 Python 教程 第4章 基本概念 上一页 字符串 下一页 字符串 字符串是 字符的序列 .字符串基本上就是一组单词. 我几乎可以保证你在每个Python程序中都要用到字符串,所以请特别留心下面这部分的内容.下面告诉你如何在Python中使用字符串. 使用单引号(') 你可以用单引号指示字符串,就如同'Quote me on this'这样.所有 ...
INTO PYTHON了,对PYTHON学习不好...& TITLE=&以后不看DIVE INTO PYTHON了,对PYTHON学习不好...& /& 白看了几天..其实看得半懂半不懂... 而且网上有个大牛觉得这本书很不掂... 还是看官方的教程比较好: 网址:http://docs.python.org/tutori ...
第 5 章 对象和面向对象 5.1. 概览 5.2. 使用 from module import 导入模块 5.3. 类的定义 5.3.1. 初始化并开始类编码 5.3.2. 了解何时去使用 self 和 __init__ 5.4. 类的实例化 5.4.1. 垃圾回收 5.5. 探索 UserDict:一个封装类 5.6. 专用类方法 5.6.1. 获得和设 ...
简介 Python语言是少有的一种可以称得上即简单又功能强大的编程语言.你将惊喜地发现Python语言是多么地简单,它注重的是如何解决问题而不是编程语言的语法和结构. Python的官方介绍是: Python是一种简单易学,功能强大的编程语言,它有高效率的高层数据结构,简单而有效地实现面向对象编程.Python简洁的语法和对动态输入的支持,再加上解释性语言的 ...}

我要回帖

更多关于 战刻夜血乙女主页 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信