Linux 版 (精华区)

发信人: emacs (被淹死的鱼), 信区: Linux
标  题: 第一章 开始了解Python -- 2
发信站: 哈工大紫丁香 (Sat Jun 15 09:45:55 2002) , 转信


1.6. 测试模块

Python模块是对象,并且有几个有用的属性。在编写模块时,你可以利用这一点更容易地
测试模块。

例 1.7. if __name__ 技巧

if __name__ == "__main__":在开始学习好东西之前,有两点要说明。第一,在 if 表达
式周围不需要小括号。第二,象C语言一样,Python使用 == 进行比较,使用 = 进行赋值
。不象C语言,Python不支持行内赋值,所以不存在把赋值当成比较的偶然情况。

那么为什么说这个特殊的 if 语句是一个技巧呢?模块是对象,并且所有的模块都有一个
内置属性 __name__。一个模块的 __name__ 的值要看你如何使用它。如果 import 模块,
那么 __name__ 的值通常为模块的文件名,不带路径或者文件扩展名。但是你也可以象一
个标准的程序一样直接运行模块,在这种情况下 __name__ 的值将是一个特别的缺省值,
 __main__。

例 1.8. 一个导入模块的 __name__

>>> import odbchelper
>>> odbchelper.__name__
'odbchelper'一旦了解这一点,你可以在模块内部为你的模块设计一个测试套件,通过在
其中加入这个 if 语句。当你直接运行模块, __name__ 的值是 __main__,所以测试套件
执行。当你导入模块, __name__ 的值就是别的东西了,所以测试套件被忽略。这样使得
在将新的模块集成到一个大程序之前开发和调试容易多了。
 
在MacPython上,需要一个额外的步聚来使得 if __name__ 技巧有效。点击窗口右上角的
黑色三角,弹出模块的属性菜单,确认Run as __main__被选中。
 
1.7. 字典 101
有必要先讲些别的,因为你需要知道字典,序列(tuples),和列表。如果你一个Perl高手
,你大概可以忽略关于字典和列表那一块,但是你仍然应该对序列进行关心。


Python的内置数据类型之一是字典,它在关键字与值之间定义了一对一的关系。这一点就
象Perl中的关联数组,Java中的 Map ,或VBScipt中的 Scripting.Dictionary 对象。 

例 1.9. 定义一个字典

>>> d = {"server":"mpilgrim", "database":"master"} 
>>> d
{'server': 'mpilgrim', 'database': 'master'}
>>> d["server"]                                    
'mpilgrim'
>>> d["database"]                                  
'master'
>>> d["mpilgrim"]                                  
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
KeyError: mpilgrim  首先,我们创建了一个拥有两个元素的新字典,并将其赋值给变量
 d。每一个元素都是一个键-值对,整个元素集合用大括号括起来。
 
  server 是一个键字,它所关联的值为 mpilgrim,用 d["server"] 来引用。 
  database 是一个键字,它所关联的值为 master,用 d["database"] 来引用。 
  你可以通过键字来得到值,但是不能通过值得到键字。所以 d["server"] 为 mpilgrim
,但是使用 d["mpilgrim"] 会引发一个异常,因为 mpilgrim 不是一个键字。
 

例 1.10. 修改一个字典

>>> d
{'server': 'mpilgrim', 'database': 'master'}
>>> d["database"] = "pubs" 
>>> d
{'server': 'mpilgrim', 'database': 'pubs'}
>>> d["uid"] = "sa"        
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'pubs'}  不能在一个字典中有重复
的键字。给一个存在的键字赋值会抹掉原来的值。 
  可以在任何时候加入新的键-值对。这种语法同修改存在的值一样。(是的,它可能某天
会给你带来麻烦,你可能认为增加了新值,但实际上只是反复地修改了同样的值,因为你
的键字没有按照你的想象改变。)
 

注意新的元素(键字为 uid,值为 sa)出现在字典中间。实际上,它只不过是一种巧合,在
第一个例子中的元素看上去是有序的。现在它们看上去无序了则更是一种巧合。


 
字典没有元素顺序的概念。说元素顺序乱了是不正确的,它们只是简单的无序。这是一个
重要的特性,它会在你想要以一种特定的,可重复的顺序(象以键字的字母表顺序)存取字
典元素的时候骚扰你。有一些实现的方法,它们只是没有加到字典中去。
 

例 1.11. 在字典中混用数据类型

>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'pubs'}
>>> d["retrycount"] = 3 
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 'retrycount': 3}
>>> d[42] = "douglas"   
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 42: 'douglas', 'retr
ycount': 3}  字典不是只用于字符串。字典的值可以是任意数据类型,包括字符串,整数
,对象,或者甚至其它的字典。在一个单个字典里,字典的值并不需要全都是同一数据类
型,可以根据需要混用和配匹。
 
  字典的关键字要严格一些,但是它们可以是字符串,整数和几种其它的类型(后面还会谈
到这一点)。也可以在一个字典中混用和配匹关键字。 

例 1.12. 从字典中删除元素

>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 42: 'douglas', 'retr
ycount': 3}
>>> del d[42] 
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 'retrycount': 3}
>>> d.clear() 
>>> d
{}  del 允许你根据键字将单个元素从字典中删除。 
  clear 会删除一个字典中所有元素。注意空的大括号所表示的集合说明一个字典没有元
素。 
1.8. 列表 101

列表是Python中使用最频繁的数据类型。如果你对列表仅有的经验是在VB中的数组或Java
中的 Lists ,那么振作起来,面对Python列表吧。

例 1.13. 定义列表

>>> li = ["a", "b", "mpilgrim", "z", "example"] 
>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[0]                                       
'a'
>>> li[4]                                       
'example'  首先我们定义了一个有5个元素的列表。注意它们保持着它们初始的顺序。这
不是一个偶然。一个列表是一个用方括号包括的有序元素集。
 
  一个列表可以象一个以0开始的数组一样使用。任何一个非空列表的第一个元素总是 li
[0]。 
  这个5元素列表的最后一个元素是 li[4],因为列表总是从0开始。 

例 1.14. 负的列表索引

>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[-1] 
'example'
>>> li[-3] 
'mpilgrim'  负数索引从列表的尾部开始向后计数存取元素。任何一个非空的列表最后一
个元素总是 li[-1]。 
  如果负数索引使你感到糊涂,象这样理解它:li[n] == li[n - len(li)]。所以在这个
列表里,li[2] == li[2 - 5] == li[-3]. 

例 1.15. 分割一个列表

>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[1:3]  
['b', 'mpilgrim']
>>> li[1:-1] 
['b', 'mpilgrim', 'z']
>>> li[0:3]  
['a', 'b', 'mpilgrim']  你可以通过指定2个索引得到列表的子集,叫做一个“分片”。
返回值是一个新的列表,它包含了列表中按顺序从第一个分片索引(这里为 li[1])开始,
直到但是不包括第二个分片索引(这里为 li[3])的所有元素。
 
  如果一个或两个分片索引是负数,分片也可以工作。如果对你有帮助,你可以这样理解
:从左向右阅读列表,第一个分片索引指定了你想要的第一个元素,第二个分片索引指定
了第一个你不想要的元素。返回的值为在其间的每个元素。
 
  列表从0开始,所以 li[0:3] 返回列表的前3个元素,开始从 li[0],直到但不包括 li
[3]。 

例 1.16. 分片缩写

>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[:3] 
['a', 'b', 'mpilgrim']
>>> li[3:] 
['z', 'example']
>>> li[:]  
['a', 'b', 'mpilgrim', 'z', 'example']  如果任一个分片索引为0,你可以将其省略,
默认为0。所以 li[:3] 同前一个例子的 li[0:3] 一样。 
  注意这里的对称写法。在这个5元素列表中,li[:3] 返回前三个元素,而 li[3:] 返回
后两个元素。实际上,li[:n] 将总是返回前 n 个元素,而 li[n:] 将返回其它的元素。
 
  如果两个分片索引均省略,将包括列表的所有元素。但是与原始的列表 li 不是同一个
,它是一个新的列表,恰好拥有与 li 全部一样的元素。li[:] 是生成一个列表拷贝的缩
写。 

例 1.17. 向列表中增加元素

>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li.append("new")               
>>> li
['a', 'b', 'mpilgrim', 'z', 'example', 'new']
>>> li.insert(2, "new")            
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new']
>>> li.extend(["two", "elements"]) 
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']  appen
d 增加单个元素到列表的尾部。 
  insert 在列表中插入单个元素。数值参数是使得列表增加的第一个元素的索引(此句原
文为:“The numeric argument is the index of the first element that gets bumpe
d out of position.”,但实在不好翻译,只暂时这样翻译,希望有什么好的建议。)。注
意列表元素不需要唯一,现在有两个独立的元素拥有 new 这个值,li[2] 和 li[6]。 
  extend 连接列表。注意不要用多个参数调用 extend ,要使用一个列表参数调用。在这
种情况下,列表有两个元素。 

例 1.18. 搜索列表

>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> li.index("example") 
5
>>> li.index("new")     
2
>>> li.index("c")       
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
ValueError: list.index(x): x not in list
>>> "c" in li           
0  index 在列表中查找值第一次的出现并返回索引值。 
  index 在列表中查找值 第一次 的出现。在本例中, new 在列表中出现了两次,在 li
[2] 和li[6],但是 index 将只返回第一个索引,2。 
  如果在列表中没有找到值,Python会引发一个异常。这一点与大部分的语言相当不同,
大部分语言将会返回某个无效索引。尽管这种处理可能看上去令人讨厌,它仍然是好东西
,因为它说明你的程序会由于源代码的问题而崩溃,好于在后面当你使用无效索引而引起
崩溃。
 
  要测试一个值是否在列表内,使用 in,如果值找到了,它返回 1 ,或者没找到则为 0
 。 
 
在Python中不存在布尔类型。在一个布尔上下文中(象 if 语句),0 是假,所有其它的数
值为真。这一点也可以扩展到其它类型。一个空串(""),一个空列表([]),和一个空字典
({})都是假,所有其它的字符串,列表,和字典是真。 

例 1.19. 从列表中除去元素

>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> li.remove("z")   
>>> li
['a', 'b', 'new', 'mpilgrim', 'example', 'new', 'two', 'elements']
>>> li.remove("new") 
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two', 'elements']
>>> li.remove("c")   
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
ValueError: list.remove(x): x not in list
>>> li.pop()         
'elements'
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two']  remove 从列表中除掉第一次出现
的值。 
  remove 仅 除掉第一次出现的值。在本例中,new 在列表中出现了两次,但是 li.remo
ve("new") 仅除掉了第一次出现的值。
 
  如果在列表中没有找到值,Python引发一个异常。它反映了 index 方法的行为。 
  pop 是一个有趣的东西。它执行两件事:除掉列表的最后一个元素,然后返回除掉的值
。注意这一点同 li[-1]不同,后者返回一个值但不改变列表,也不同于 li.remove(valu
e),后者改变列表但不返回值。 

例 1.20. 列表操作符

>>> li = ['a', 'b', 'mpilgrim']
>>> li = li + ['example', 'new'] 
>>> li
['a', 'b', 'mpilgrim', 'example', 'new']
>>> li += ['two']                
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two']
>>> li = [1, 2] * 3              
>>> li
[1, 2, 1, 2, 1, 2]  列表也可以用 + 操作符连接起来。list = list + otherlist 相当
于 list.extend(otherlist)。但是 + 操作符将连接后的列表作为一个值返回,而 exten
d 仅修改存在的列表。 
  Python支持 += 操作符。li += ['two'] 相当于 li = li + ['two']。+= 操作符可用于
列表,字符串,和整数,并且它也可以在用户定义类中被重载。(第三章会有更多的类) 
  * 操作符作为一个重复符可用在列表上。li = [1, 2] * 3 相当于 li = [1, 2] + [1,
 2] + [1, 2], 将三个列表连成一个。
 
1.9. 序列 101

序列是不可变列表。一旦创建了一个序列就不能以任何方式改变它。

例 1.21. 定义序列

>>> t = ("a", "b", "mpilgrim", "z", "example") 
>>> t
('a', 'b', 'mpilgrim', 'z', 'example')
>>> t[0]                                       
'a'
>>> t[-1]                                      
'example'
>>> t[1:3]                                     
('b', 'mpilgrim')  序列的定义同列表的定义方式相同,除了整个元素集是用小括号包围
的而不是方括号。 
  序列的元素象列表一样按定义的次序进行排序。序列的索引象列表一样从0开始,所以一
个非空序列的第一个元素总是 t[0]。 
  负数索引象列表一样从序列尾部开始计数。 
  分片也可以使用,就象列表一样。注意当分割一个列表时,会得到一个新的列表;当分
割一个序列时,会得到一个新的序列。 

例 1.22. 序列没有方法

>>> t
('a', 'b', 'mpilgrim', 'z', 'example')
>>> t.append("new")    
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'append'
>>> t.remove("z")      
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'remove'
>>> t.index("example") 
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'index'
>>> "z" in t           
1  你不能向序列增加元素。序列没有 append 或 extend 方法。 
  你不能从序列中除掉元素。序列没有 remove 或 pop 方法。 
  你不能在序列中查找元素。序列没有 index 方法。 
  然而,你可以使用 in 来看一看是否一个元素存在于序列中。 

那么序列有什么好处呢?

序列比列表操作速度快。如果你定义了一个值集合常量,并且唯一要用它做的是不断地遍
历它,使用序列代替列表。 
记得我说过字典关键字可以是整数,字符串和“几种其它的类型”吗?序列就是那些类型
之一。序列可以在字典中被用作关键字,但是列表不行。[2] 
序列用在字符串格式化,这一点我们会很快看到。 
 
序列可以转化成列表,反之亦然。内置的 tuple 函数接收一个列表,返回一个有着相同元
素的序列。而 list 函数接收一个序列,返回一个列表。从效果上看,tuple 冻结一个列
表,而 list 解冻一个序列。 
1.10. 定义变量
即然你认为已经了解了字典,序列和列表的所有知识,就让我们回到我们的例子程序 odb
chelper.py。


Python象大多数其它语言一样有局部和全局变量,但是它没有明显的变量声明。变量通过
赋值产生,当超出作用范围时自动消灭。

例 1.23. 定义 myParams 变量

if __name__ == "__main__":
    myParams = {"server":"mpilgrim", \
                "database":"master", \
                "uid":"sa", \
                "pwd":"secret" \
                }这里有几个有趣的地方。首先,注意一下缩排。if 语句是代码块,需
要象函数一样缩排。

其次,变量的赋值是一条命令被分成了几行,用反斜线(“\”)作为续行符。

 
当一条命令用续行符(“\”)分割成多行时,后续的行可以以任何方式缩排,Python通常的
严格的缩排规则不需遵守。如果你的Python IDE自由对后续行进行了缩排,你应该把它当
成是缺省处理,除非你有特别的原因不这么做。 
 
严格地讲,在小括号,方括号或大括号中的表达式(如定义字典)可以用或者不用续行符(“
\”)分割成多行。甚至在不必需的时候,我也喜欢包括反斜线,因为我认为这样会让代码
读起来容易,但那只是风格的问题。
 

第三,你从未声明过变量 myParams,你只是给它赋了一个值。这点就象是VBScript没有设
置 option explicit 选项。幸运的是,不象VBScript,Python不允许你引用一个未被赋值
的变量,试图这样做会引发一个异常。

例 1.24. 引用未赋值的变量

>>> x
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
NameError: There is no variable named 'x'
>>> x = 1
>>> x
1早晚有一天你会为此而感谢Python。


--

※ 来源:.哈工大紫丁香 http://bbs.hit.edu.cn [FROM: 211.93.34.115]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:212.116毫秒