《dinv into python》开始了解pyth…

来源:互联网 发布:淘宝店要装修 编辑:程序博客网 时间:2024/06/06 08:48

1.2. 声明函数



象大多数其它语言,Python拥有函数。但是不象C++或Java,它没有独立的接口声明和实现声明。一旦需要一个函数,声明它,编码就行了。
根据上个例子:
dive into python有写道:
def buildConnectionString(params):

有几件事情需要注意的。首先,关键字 def为函数声明的开始。不象VB,Python并不区分有返回值的函数与无返回值的函数。它没有子程序。全部都是函数,所有的函数都以def 开始。

其次,函数没有定义返回的数据类型。实际上,甚至不需要指定是否会返回一个值。函数并不关心第一种情况或第二种情况。如果函数执行了一个return 语句,它将返回一个值,否则会返回 None (Python的空值)。

第三,参数 params并不需要指明数据类型。在Python中,变量不需要被明确类型。Python会指出一个变量是什么类型,并在内部保持记录。

 

1.3. 文档化函数

可以通过给出一个文档字符串文档化一个Python函数。

例 1.4. 定义buildConnectionString函数的文档字符串

def buildConnectionString(params):    """Build a connection string from a dictionary of parameters.    Returns string."""

三重双引号的引用表示一个多行字符串。在定义一个文档字符串的时候,你会看到它们经常被使用。

任何在三重双引号中的东西都是函数的文档字符串,它们用来说明函数可以做什么。如果存在文档字符串,它必须要在函数中的被首先定义(也就是说在冒号后面被定义)。在技术上不需要给函数定义文档字符串,但是你应该这样做。我相信在你所参加过的每一个编程课上已经听到过这一点,但是Python会给你一些其它的机制:文档字符串在运行时可作为函数的属性。

Note

许多PythonIDE使用文档字符串来提供上下文相关提示,这样当你敲入一个函数名,它的文档字符串将显示为提示框。这一点相当的有用,但是完全要看你写的文档字符串的好坏了。

1.4.每个都是对象

万一你没听到,我刚才说了Python函数有属性,那些属性在运行时可用。

函数,如同在Python中的每个东西,是一个对象。

例 1.5.存取 buildConnectionString函数的文档字符串

>>> import odbchelper                              1

>>>params ={"server":"mpilgrim","database":"master", "uid":"sa", "pwd":"secret"}>>>print odbchelper.buildConnectionString(params)2 server=mpilgrim;uid=sa;database=master;pwd=secret>>>print odbchelper.buildConnectionString.__doc__ 3 Build aconnection string from a dictionaryReturns string.

 

 

1第一行将 odbchelper程序作为模块导入。一旦你导入一个模块,你可以引用它的任何的公共函数,类,或属性。模块可以通过这种方法来使用其它模块的功能,也可以在IDE中实现它。这是一个很重要的概念,在后面将谈得更多。2当你想使用定义在被导入模块中的函数时,必须包括模块的名字。所以你不能只使用buildConnectionString,而应该为odbchelper.buildConnectionString。如果你曾经用过Java中的类,对于这一点应该非常熟悉。3如你想象的替换调用函数,我们可以访问了函数的属性,__doc__。

在Python中每个东西都是对象,并且几乎每个东西都有属性和方法。[1] 所有的函数都有一个内置的属性__doc__,它会返回在函数源代码中定义的文档字符串。

这一点如此重要,所以我会在前几讲中重复它,以防你忘记了:在Python中的每个东西都是对象。字符串是对象。列表是对象。函数是对象。甚至模块是对象,这一点我们很快会看到。


 下面是我的test结果

《dinv <wbr>into <wbr>python》开始了解python
 

1.5. 缩排代码

Python函数没有明显的 beginend,或任何括号或大括号,可以标识函数从哪里开始,又在哪里结束。唯一的分隔是通过一个冒号(:)和代码本身的缩排来表示。

例 1.6. 缩排buildConnectionString 函数

def buildConnectionString(params):    """Build a connection string from a dictionary of parameters.    Returns string."""    return ";".join(["%s=%s" % (k, params[k]) for k in params.keys()])

代码块(函数,if 语句,for循环,等等)通过它们的缩排来定义。缩排表示块的开始,非缩排表示结束,不存在明显的括号,大括号,或关键字。这就意味着空白是有意义的,并且要一致。在这个例子中,函数代码(包括文档字符串)缩近了4个空格。不一定非要是4个,只要一致就可以了。第一行没有缩近,则不算在函数内。

在经过开始的一些反对和同Fortran相比后的挖苦之后,你将会心平气和地对待它,开始理解它的好处。一个主要的好处是,所有的Python程序看上去差不多,因为缩排是语言的要求而不是风格问题。这样就更容易阅读和理解他人的Python代码。

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__的值就是别的东西了,所以测试套件被忽略。这样使得在将新的模块集成到一个大程序之前开发和调试容易多了。

Tip

在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"} 1>>> d{'server': 'mpilgrim', 'database': 'master'}>>> d["server"]                                    2'mpilgrim'>>> d["database"]                                  3'master'>>> d["mpilgrim"]                                  4Traceback (innermost last):  File "<interactive input>", line 1, in ?KeyError: mpilgrim
1

首先,我们创建了一个拥有两个元素的新字典,并将其赋值给变量d。每一个元素都是一个键-值对,整个元素集合用大括号括起来。

2server 是一个键字,它所关联的值为 mpilgrim,用d["server"] 来引用。3database 是一个键字,它所关联的值为 master,用 d["database"] 来引用。4

你可以通过键字来得到值,但是不能通过值得到键字。所以 d["server"]mpilgrim,但是使用d["mpilgrim"] 会引发一个异常,因为 mpilgrim 不是一个键字。

 

《dinv <wbr>into <wbr>python》开始了解python

例 1.10. 修改一个字典

>>> d{'server': 'mpilgrim', 'database': 'master'}>>> d["database"] = "pubs" 1>>> d{'server': 'mpilgrim', 'database': 'pubs'}>>> d["uid"] = "sa"        2>>> d{'server': 'mpilgrim', 'uid': 'sa', 'database': 'pubs'}
1不能在一个字典中有重复的键字。给一个存在的键字赋值会抹掉原来的值。2

可以在任何时候加入新的键-值对。这种语法同修改存在的值一样。(是的,它可能某天会给你带来麻烦,你可能认为增加了新值,但实际上只是反复地修改了同样的值,因为你的键字没有按照你的想象改变。)

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

Note

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

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

>>> d{'server': 'mpilgrim', 'uid': 'sa', 'database': 'pubs'}>>> d["retrycount"] = 3 1>>> d{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 'retrycount': 3}>>> d[42] = "douglas"   2>>> d{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 42: 'douglas', 'retrycount': 3}
1

字典不是只用于字符串。字典的值可以是任意数据类型,包括字符串,整数,对象,或者甚至其它的字典。在一个单个字典里,字典的值并不需要全都是同一数据类型,可以根据需要混用和配匹。

2

字典的关键字要严格一些,但是它们可以是字符串,整数和几种其它的类型(后面还会谈到这一点)。也可以在一个字典中混用和配匹关键字。

 

《dinv <wbr>into <wbr>python》开始了解python

例1.12. 从字典中删除元素

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

1.8. 列表101

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

例 1.13. 定义列表

>>> li = ["a", "b", "mpilgrim", "z", "example"] 1>>> li['a', 'b', 'mpilgrim', 'z', 'example']>>> li[0]                                       2'a'>>> li[4]                                       3'example'
1

首先我们定义了一个有5个元素的列表。注意它们保持着它们初始的顺序。这不是一个偶然。一个列表是一个用方括号包括的有序元素集。

2一个列表可以象一个以0开始的数组一样使用。任何一个非空列表的第一个元素总是li[0]3这个5元素列表的最后一个元素是li[4],因为列表总是从0开始。

例 1.14.负的列表索引

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

例 1.15. 分割一个列表

>>> li['a', 'b', 'mpilgrim', 'z', 'example']>>> li[1:3]  1['b', 'mpilgrim']>>> li[1:-1] 2['b', 'mpilgrim', 'z']>>> li[0:3]  3['a', 'b', 'mpilgrim']
1

你可以通过指定2个索引得到列表的子集,叫做一个“分片”。返回值是一个新的列表,它包含了列表中按顺序从第一个分片索引(这里为li[1])开始,直到但是不包括第二个分片索引(这里为 li[3])的所有元素。

2

如果一个或两个分片索引是负数,分片也可以工作。如果对你有帮助,你可以这样理解:从左向右阅读列表,第一个分片索引指定了你想要的第一个元素,第二个分片索引指定了第一个你不想要的元素。返回的值为在其间的每个元素。

3列表从0开始,所以 li[0:3]返回列表的前3个元素,开始从 li[0],直到但不包括 li[3]

例 1.16. 分片缩写

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

例 1.17.向列表中增加元素

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

extend 连接列表。注意不要用多个参数调用 extend,要使用一个列表参数调用。在这种情况下,列表有两个元素。

 

《dinv <wbr>into <wbr>python》开始了解python

例 1.18. 搜索列表

>>> li['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']>>> li.index("example") 15>>> li.index("new")     22>>> li.index("c")       3Traceback (innermost last):  File "<interactive input>", line 1, in ?ValueError: list.index(x): x not in list>>> "c" in li           40
1index在列表中查找值第一次的出现并返回索引值。2index 在列表中查找值 第一次的出现。在本例中, new 在列表中出现了两次,在 li[2]li[6],但是 index 将只返回第一个索引,23

如果在列表中没有找到值,Python会引发一个异常。这一点与大部分的语言相当不同,大部分语言将会返回某个无效索引。尽管这种处理可能看上去令人讨厌,它仍然是好东西,因为它说明你的程序会由于源代码的问题而崩溃,好于在后面当你使用无效索引而引起崩溃。

4要测试一个值是否在列表内,使用in,如果值找到了,它返回 1 ,或者没找到则为 0Note在Python中不存在布尔类型。在一个布尔上下文中(象 if 语句),0是假,所有其它的数值为真。这一点也可以扩展到其它类型。一个空串(""),一个空列表([]),和一个空字典({})都是假,所有其它的字符串,列表,和字典是真。

例 1.19. 从列表中除去元素

>>> li['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']>>> li.remove("z")   1>>> li['a', 'b', 'new', 'mpilgrim', 'example', 'new', 'two', 'elements']>>> li.remove("new") 2>>> li['a', 'b', 'mpilgrim', 'example', 'new', 'two', 'elements']>>> li.remove("c")   3Traceback (innermost last):  File "<interactive input>", line 1, in ?ValueError: list.remove(x): x not in list>>> li.pop()         4'elements'>>> li['a', 'b', 'mpilgrim', 'example', 'new', 'two']
1remove 从列表中除掉第一次出现的值。2

remove 除掉第一次出现的值。在本例中,new在列表中出现了两次,但是 li.remove("new") 仅除掉了第一次出现的值。

3如果在列表中没有找到值,Python引发一个异常。它反映了index 方法的行为。4pop是一个有趣的东西。它执行两件事:除掉列表的最后一个元素,然后返回除掉的值。注意这一点同li[-1]不同,后者返回一个值但不改变列表,也不同于li.remove(value),后者改变列表但不返回值。

例 1.20. 列表操作符

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

* 操作符作为一个重复符可用在列表上。li = [1, 2] * 3 相当于 li= [1, 2] + [1, 2] + [1, 2], 将三个列表连成一个。

 

1.9. 序列101

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

例 1.21.定义序列

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

例 1.22. 序列没有方法

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

那么序列有什么好处呢?

  • 序列比列表操作速度快。如果你定义了一个值集合常量,并且唯一要用它做的是不断地遍历它,使用序列代替列表。
  • 记得我说过字典关键字可以是整数,字符串和“几种其它的类型”吗?序列就是那些类型之一。序列可以在字典中被用作关键字,但是列表不行。[2]
  • 序列用在字符串格式化,这一点我们会很快看到。

Note序列可以转化成列表,反之亦然。内置的tuple 函数接收一个列表,返回一个有着相同元素的序列。而 list 函数接收一个序列,返回一个列表。从效果上看,tuple 冻结一个列表,而list 解冻一个序列。

1.10.定义变量

即然你认为已经了解了字典,序列和列表的所有知识,就让我们回到我们的例子程序odbchelper.py

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

例 1.23. 定义myParams 变量

if __name__ == "__main__":    myParams = {"server":"mpilgrim", \                "database":"master", \                "uid":"sa", \                "pwd":"secret" \                }

这里有几个有趣的地方。首先,注意一下缩排。if 语句是代码块,需要象函数一样缩排。

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

Note当一条命令用续行符(“\”)分割成多行时,后续的行可以以任何方式缩排,Python通常的严格的缩排规则不需遵守。如果你的PythonIDE自由对后续行进行了缩排,你应该把它当成是缺省处理,除非你有特别的原因不这么做。Note

严格地讲,在小括号,方括号或大括号中的表达式(如定义字典)可以用或者不用续行符(“\”)分割成多行。甚至在不必需的时候,我也喜欢包括反斜线,因为我认为这样会让代码读起来容易,但那只是风格的问题。

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

例 1.24. 引用未赋值的变量

>>> xTraceback (innermost last):  File "<interactive input>", line 1, in ?NameError: There is no variable named 'x'>>> x = 1>>> x1

早晚有一天你会为此而感谢Python。


 

1.11. 格式化字符串

odbchelper.py 所有实际的工作是用一行代码完成的,下面就是。

    return ";".join(["%s=%s" % (k, params[k]) for k in params.keys()])

不要恐慌。忽略别的东西,集中在中间部分,它是字符串格式化表达式。(如果你是一个C高手,也许可以忽略这部分。)

例 1.25.中间部分

"%s=%s" % (k, params[k])

Python支持将值的格式化输出到字符串中,象C语言中的 sprintf 函数。最基本的用法是简单地在 %s 占位符的地方插入一个值。

例 1.26.字符串格式化介绍

>>> params = {"uid":"sa", "pwd":"secret"}>>> k = "uid">>> "%s=%s" % (k, params[k]) 1'uid=sa'>>> k = "pwd">>> "%s=%s" % (k, params[k]) 2'pwd=secret'
1

整个表达式计算结果为一个字符串。(原文:“The wholeexpressionevaluates to a string.”估且如此翻译。) 第一个 %s 被变量 k 的值替换;第二个 %s 被字典 params 中的键字为k 的值替换。在字符串中所有其它的字符(在这个例子中,是等号)按原样保留。

2这个表达式可用在字典中的任一关键字。(“哈,那意味着它可用于字典中每个 关键字...在一个循环中..”不要太超前,马上就来了。)

注意(k,params[k])是一个序列。我说过它们对某些东西有用。

你可能一直在想做了这么多工作只是为了做简单的字符串连接,你想的不错;只不过字符串格式化不只是连接。它甚至不仅仅是格式化。它也是强制类型转换。

例 1.27.字符串格式化对比字符串连接

>>> uid = "sa">>> pwd = "secret">>> print pwd + " is not a good password for " + uid      1secret is not a good password for sa>>> print "%s is not a good password for %s" % (pwd, uid) 2secret is not a good password for sa>>> userCount = 6>>> print "Users connected: %d" % (userCount, )           3 4Users connected: 6>>> print "Users connected: " + userCount                 5Traceback (innermost last):  File "<interactive input>", line 1, in ?TypeError: cannot add type "int" to string
1+ 是字符串连接操作符。2在这个简单例子中,字符串格式化实现与连接一样的结果。3(userCount, )是一个有一个元素的序列。是的,语法有一点奇怪,但是对此有更好的理由。4字符串格式化通过将 %s 替换成 %d即可处理整数。还记得我说过你需要知道Python会什么时候和会如何将数据强制转换成不同的类型吗?这就是其中一例。5试图将一个字符串同一个非字符串连接会引发一个异常。字符串连接只能在每个都是字符串时起作用。

1.13.连接列表和分割字符串

你有了一个形如 key=value的键-值对列表,并且想将它们合成为单个字符串。为了将任意字符串列表连接成单个字符串,使用一个字符串对象的join 方法。

例 1.32. 在buildConnectionString中连接字符串

    return ";".join(["%s=%s" % (k, params[k]) for k in params.keys()])

在我们继续之前有一个有趣的地方。我一直在重复函数是对象,字符串是对象,每个东西都是对象。你也许认为我的意思是说字符串变量 是对象。但是不,仔细地看一下这个例子,你将会看到字符串 ";" 本身是一个对象,你在调用它的join 方法。

总之, join方法将列表元素连接成单个字符串,每个元素用一个分号隔开。分隔符不需要是一个分号;它甚至不必是单个字符。它可以是任何字符串。

Importantjoin只用用于字符串列表;它不进行任何的类型强制转换。连接一个存在一个或多个非字符串元素的列表将引发一个异常。

例 1.33.odbchelper.py 的输出

>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}>>> ["%s=%s" % (k, params[k]) for k in params.keys()]['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']>>> ";".join(["%s=%s" % (k, params[k]) for k in params.keys()])server=mpilgrim;uid=sa;database=master;pwd=secret

接着,上面的字符串从 help函数返回,被调用块打印出来,这样就给出在你开始阅读本章时令你感到吃惊的输出。

历史记录 当我开始学Python时,我以为 join应该是列表的方法,它会使用分隔符作为一个参数。看上去有些矛盾的原因纯粹由于历史造成的。在Python1.6之前,字符串完全没有这些有用的方法。有一个独立的 string模块拥有所有的字符串函数,每个函数使用一个字符串作为它的第一个参数。这些函数被认为足够重要,所以它们移到字符串中去了,这当然是件好事情。但是,无论好坏,join 跟它们一起,这就是我们看到的。

你可能在想是否存在一个适当的方法来将字符串分割成一个列表。当然有,它叫做 split

例 1.34. 分割字符串

>>> li = ['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']>>> s = ";".join(li)>>> s'server=mpilgrim;uid=sa;database=master;pwd=secret'>>> s.split(";")    1['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']>>> s.split(";", 1) 2['server=mpilgrim', 'uid=sa;database=master;pwd=secret']
1

splitjoin相反,通过将一个字符串分割成多元素列表。注意,分隔符(“;”)被完全去掉了,它没有在返回的列表中的任意元素中出现。

2split接受一个可选的第二个参数,它是要分割的次数。(哦,可选参数...你将会在下一章中学会如何在你自已的函数中实现它。)Note

string.split(delimiter, 1)是一个有用的技术,在你想要搜索一个子串,然后处理字串前面的东西(即列表中第一个元素)和其后的东西(即列表中第二个元素)时,使用这个技术。

 

《dinv <wbr>into <wbr>python》开始了解python


 

1.14.小结

odbchelper.py 程序和它的输出现在应该非常清楚了。

例 1.35.odbchelper.py

def buildConnectionString(params):    """Build a connection string from a dictionary of parameters.    Returns string."""    return ";".join(["%s=%s" % (k, params[k]) for k in params.keys()])if __name__ == "__main__":    myParams = {"server":"mpilgrim", \                "database":"master", \                "uid":"sa", \                "pwd":"secret" \                }    print buildConnectionString(myParams)

例 1.36.odbchelper.py 的输出

server=mpilgrim;uid=sa;database=master;pwd=secret

在深入下一章之前,确保你可以无困难地完成下面的事情:

  • 使用Python IDE来交互式地测试表达式
  • 编写Python模块,以便让它们也能够象标准程序一样运行,至少为测试目的
  • 导入模块及调用它们的函数
  • 声明函数及使用文档字符串,局部变量,和适当的缩近
  • 定义字典,序列,和列表
  • 存取任一个对象的属性和方法,包括字符串,列表,字典,函数和模块
  • 通过字符串格式化连接值
  • 映射列表变成其它的列表
  • 分割字符串成为列表并且连接列表成为字符串

 

下面第一章已经完毕,大体上懂得python是什么玩意