首页 > 深入Python > 对向对象框架 > 一次赋多个值 | << >> |
diveintopython.org |
|
Python for experienced programmers |
在Python中最酷的程序简写之一就是使用序列一次赋多个值。
>>> v = ('a', 'b', 'e') >>> (x, y, z) = v >>> x 'a' >>> y 'b' >>> z 'e'
v 是一个三元素的序列,(x, y, z) 是一个有三个变量的序列。将一个序列赋给另一个,会将 v 的每个值依次赋给每个变量。 |
它有着许多的用处。当构建可重用的模块时,你经常需要给一个名字赋以一系列的值。在C或C++中,你将使用 enum 并且手工地列出每个常量和它所对应的值,当值是连续的时候显得特别烦琐。在Python中,你可以使用内置的 range 函数来迅速地给多个变量赋予连续值。
>>> range(7) [0, 1, 2, 3, 4, 5, 6] >>> (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7) >>> MONDAY 0 >>> TUESDAY 1 >>> SUNDAY 6
使用这种技术,你可以构建返回多值的函数,只要通过返回包含所有值的一个序列。调用者可以把返回值看成一个序列,或者将值赋给单个变量。
>>> import os >>> os.path.split("/music/ap/mahadeva.mp3") ('/music/ap', 'mahadeva.mp3') >>> (filepath, filename) = os.path.split("/music/ap/mahadeva.mp3") >>> filepath '/music/ap' >>> filename 'mahadeva.mp3' >>> (shortname, extension) = os.path.splitext(filename) >>> shortname 'mahadeva' >>> extension '.mp3'
只要有可能,你最好使用在 os 和 os.path 中的函数来处理对文件,目录,和路径的操作。这些模块是对于平台特定模块的封装产物,所以象 os.path.split 之类的函数可以工作在UNIX,Windows,MacOS,和其它任何支持Python的平台上。 |
利用多变量赋值甚至有更多可以做的。它可以用在遍历一个序列列表的时候,意味着你可将它用于 for 循环和列表映射中。你也许不认为序列列表是你每天都要遇到的东西,但是实际上字典的 items 方法就返回一个序列列表,每个序列的形式为(key,value)。所以多变量赋值允许你通过简单的方法来遍历字典的元素。
>>> for k, v in os.environ.items() ... print "%s=%s" % (k, v) USERPROFILE=C:\Documents and Settings\mpilgrim OS=Windows_NT PROCESSOR_IDENTIFIER=x86 Family 6 Model 6 Stepping 10, GenuineIntel COMPUTERNAME=MPILGRIM USERNAME=mpilgrim […snip…]
使用多变量赋值不是绝对必需的。它是一种方便的简写,且可以让你的代码更加可读,特别是当处理字典时(通过 items 方法)。但是如果发现你迫使自已的代码通过种种周折(为了以正确的形式得到数据),只是为了让你可以一次给两个变量赋值,可能就不值得那么做了。 |
>>> print "\n".join(["%s=%s" % (k, v) for k, v in os.environ.items()]) USERPROFILE=C:\Documents and Settings\mpilgrim OS=Windows_NT PROCESSOR_IDENTIFIER=x86 Family 6 Model 6 Stepping 10, GenuineIntel COMPUTERNAME=MPILGRIM USERNAME=mpilgrim […snip…]
多变量赋值也可以用于列表映射,使用这种简捷的方法来将字典映射成列表。本例中,我们通过将列表连接成一个字符串使得这种用法更深一步。注意它的输出与前例中的 for 循环一样。这就是为什么你在Python中看到那么少的 for 循环的原因;许多复杂的事情可以不用它们完成。你可以讨论是否这种方法更易读,但是它相当快,因为只有一条输出语句而不是许多。 |
例 3.29. 在 MP3FileInfo 中的多变量 for 循环
tagDataMap = {"title" : ( 3, 33, stripnulls), "artist" : ( 33, 63, stripnulls), "album" : ( 63, 93, stripnulls), "year" : ( 93, 97, stripnulls), "comment" : ( 97, 126, stripnulls), "genre" : (127, 128, ord)} . . . if tagdata[:3] == "TAG": for tag, (start, end, parseFunc) in self.tagDataMap.items(): self[tag] = parseFunc(tagdata[start:end])
tagDataMap 是一个类属性,它定义了我们正在一个MP3文件中所查找的标记。标记被保存在定长的字段中;一旦我们读出文件的最后128个字节,字节3到32是歌曲的题目,33-62是歌手名字,63-92是专集名字,等等。注意 tagDataMap 是一个序列字典,每个序列包含两个整数和一个函数引用。 |
|
这个看上去有些复杂,其实不是。for 变量结构与通过 items 返回的列表元素的结构相匹配。记住,items 返回一个形式为(key,value)的序列列表。列表的第一个元素是("title", (3, 33, <function stripnulls>)),所以循环的第一轮,tag 得到 "title",start 得到 3,end 得到 33,而 parseFunc 得到函数 stripnulls。 |
|
现在我们已经提取出了单个MP3标记的所有参数,保存标记数据很容易。我们从 start 到end 划分 tagdata 以得到这个标记的实际数据,调用 parseFunc 来对数据进行后续处理,然后将它作为关键字的值赋给伪字典 self 的 tag 关键字。在遍历了 tagDataMap 中所有元素之后, self 拥有所有标记的值,并且你知道那看上去象什么。 |
进一步阅读 |
|
« for 循环 | 更多关于模块 » |