learnpython09Word文档格式.docx
- 文档编号:6498588
- 上传时间:2023-05-06
- 格式:DOCX
- 页数:57
- 大小:43.29KB
learnpython09Word文档格式.docx
《learnpython09Word文档格式.docx》由会员分享,可在线阅读,更多相关《learnpython09Word文档格式.docx(57页珍藏版)》请在冰点文库上搜索。
另一个常见的字典操作现在也是标准的字典特性了。
如果你有一个字典oneDict,
而想用另一个不同的字典otherDict的内容替换它,只需要用:
oneDict.update(otherDict)
这与下面的代码相同:
forkeyinotherDict.keys():
oneDict[key]=otherDict[key]
如果在update()操作前oneDict与otherDict共享一些键时,在oneDict中的
键关联的旧值将被删除掉。
这也许是你所想要的(通常是这样,这也是为什么选
择这个操作并称之为update()的原因)。
如果这不是你期望的,那么要做的也许
是抱怨(引发异常),如下:
defmergeWithoutOverlap(oneDict,otherDict):
newDict=oneDict.copy()
forkeyinotherDict.keys():
ifkeyinoneDict.keys():
raiseValueError,"
thetwodictionariesaresharingkeys!
"
newDict[key]=otherDict[key]
returnnewDict
或者把二者的值结合为一个元组,例如:
defmergeWithOverlap(oneDict,otherDict):
274
newDict[key]=oneDict[key],otherDict[key]
else:
为了说明前面三个算法的不同,考虑下面两个字典:
phoneBook1={'
michael'
:
'
555-1212'
'
mark'
554-1121'
emily'
556-0091'
}
phoneBook2={'
latoya'
555-1255'
667-1234}
如果phoneBook1可能是过时的,而phoneBook2更新一些但不够完整,那么正
确的用法可能是phoneBooke1.update(phoneBook2)。
如果认为两个电话本不
应该有重复的键时,使用newBook=mergeWithoutOverlap(phoneBook1,
phoneBook2)可以让你知道假设是否有错。
最后一种,如果一个是家里的电话本
而另一个是办公室的电话本,那么只要是后续的引用newBook['
]的代码
能够处理newBook['
]是元组('
'
667-1234'
)这一事实,就可
以用:
newBook=mergeWithoutOverlap(phoneBook1,phoneBook2)
拷贝:
copy模块
回到拷贝主题上来:
[:
]和.copy()技巧适用于90%的情况。
如果你正按照Python
的精神,编写可以处理任何参数类型的函数,有时需要拷贝X而不管X是什么。
这时就需要copy模块。
它提供了两个函数,copy和deepcopy。
第一个就像序列
的分片操作[:
]或是字典的copy方法。
第二个函数更微妙并且与深度嵌套结构有
关(这正是deepcopy的意思)。
例如用分片操作[:
]完整地拷贝listOne。
这个
技术产生了新的列表,如果原来的列表中的内容是不变的对象,如数字或字符串,
这个拷贝就是“真正的”拷贝。
然而假设listOne的第一项是一个字典(或任何
其他容易变化的对象),那么listOne的拷贝的第一项只是对同一个字典的新的
引用。
所以如果你修改了那个字典,显然listOne和它的拷贝都修改了。
用一个
例子可以看得更清楚些:
>
importcopy
listOne=[{"
name"
"
Willie"
"
city"
Providence,RI"
},1,"
tomato"
3.0]
275
listTwo=listOne[:
]#orlistTwo=copy.copy(listOne)
listThree=copy.deepcopy(listOne)
listOne.append("
kid"
)
listOne[0]["
]="
SanFrancisco,CA"
printlistOne,listTwo,listThree
[{'
name'
Willie'
city'
SanFrancisco,CA'
},1,'
tomato'
3.0,'
kid'
'
Providence,RI'
正如你所见,直接修改listOne仅仅修改了listOne。
对listOne的第一项的修
改影响到listTwo,但没有影响listThree。
这就是浅度拷贝([:
])和深度拷
贝的区别。
copy模块的函数知道如何拷贝可以拷贝的内置函数(注1),包括类和
实例。
排序
在第二章你知道列表有一个排序方法,有时你想要遍历整个排好序的列表而不想
影响列表的内容。
或者你也许想列出一个排好序的元组,而元组是不可变的,不
允许有排序的方法。
唯一的解决办法是拷贝一个列表,然后派序列表。
例如:
listCopy=list(myTuple)
listCopy.sort()
foriteminlistCopy:
printitem
#或者做别的任何事情
这也是处理那些没有内在顺序的数据结构的办法,例如字典。
字典非常快的一个
原因是实现时保留了改变键的顺序的权利。
这其实不是一个问题,因为你可以拷
贝字典的键然后遍历它:
keys=myDict.keys()
#返回字典的未排序的键
keys.sort()
forkeyinkeys:
#答应以键为序的健值对
printkey,myDict[key]
列表的sort方法使用的是Python的标准比较方案。
但有时你需要别的方案。
例
注1:
有些对象是不可拷贝的,如模块、文件对象和套接字。
记住,文件对象与磁盘上的文
件是不同的。
276
如当你对一个单词列表排序时,大小写也许是没有意义的。
而对字符串的标准比
较中,所有大写字母都在小写之前,所以'
Baby'
小于'
apple'
而'
baby'
大于
。
为了进行大小写无关排序,你需要定义一个有两个参数的函数,并且根
据第一个参数是小于,等于或大于第二个参数,分别返回-1,0,1。
所以你可以
这样写:
defcaseIndependentSort(something,other):
...something,other=string.lower(something),string.lower(other)
...returncmp(something,other)
...
testList=['
this'
is'
A'
sorted'
List'
testList.sort()
printtestList
['
testList.sort(caseIndependentSort)
我们使用内置的函数cmp来完成比较工作。
我们的排序函数只是把两项变成小写
字母然后排序。
也请注意小写转换是在比较函数局部范围内的,所以列表中的元
素并没有因排序而修改。
随机:
random模块
怎样随机排列一个序列呢?
比如一个文本行的列表。
最简单的办法是使用random
模块里的choice函数,它随机地返回序列的元素作为它的参数(注2)。
为了避
免重复地得到同样的行,记住删除已经选择了的项。
当操作一个列表对象时,使
用remove方法:
whilemyList:
#当myList空时停止循环
element=random.choice(myList)
myList.remove(element)
printelement,
如果你需要随机处理一个非列表对象,通常最简单的办法是把它转换为一个列表,
注2:
random模块提供了很多有用的函数,例如random函数,它返回一个介于0和1之间
的随机浮点数。
277
然后对这个列表作随机处理,而不是对每种数据类型都采用新的办法。
这似乎是
一个浪费的办法,也许要产生一个很巨大的列表。
然而一般来说,对你似乎很大
的数据,对于计算机来说可能不那么大,感谢Python的引用系统。
而且不用对每
种数据类型采用不同的方法,所节约的时间是很多的。
Python的设计初衷就是要
节约时间;
如果那意味着运行一个稍慢一点或者大一点的程序,那就让它这样吧。
如果你正在处理大量的数据,也许值得优化。
但只有当确实需要优化时才去优化,
否则将是浪费时间。
定义新的数据结构
对于数据结构来说,不要重复发明轮子这一原则尤其重要。
例如,Python的列表
和字典也许不是你习惯于使用的,但如果这些数据结构可以满足要求,你应当避
免设计自己的数据结构,它们使用的算法已经在各种情形下测试过,并且快而稳
定。
但有时这些算法的接口对某个特别的任务不方便。
例如,计算机科学的教科书中经常用其他数据结构术语如队列、堆栈来描述算法。
为了使用这些算法,定义与这些数据结构有同样方法的数据结构也许是有意义的。
(比如堆栈的pop和push,或者队列的enqueue和dequeue)。
而且,重用内置的
列表类型来实现堆栈也是有意义的。
换句话说,你需要行为像堆栈但却是基于列
表的结构。
最简单的办法是用一个类来包裹一个列表。
为了最低限度地实现一个
类,你可以这样写:
classStack:
def__init__(self,data):
self._data=list(data)
defpush(self,item):
self._data.append(item)
defpop(self):
item=self._data[-1]
delself._data[-1]
returnitem
下面的语句不仅易写,易懂,而且易读,易用。
thingsToDo=Stack(['
writetomom'
invitefriendover'
washthe
])
278
thingsToDo.push('
dothedishes'
printthingsToDo.pop()
dothedishes
printthingsToDo.pop()
washthekid
在上面的堆栈类中用了两个标准的Python命名习惯,第一个是类名由大写字母开
始,以便与函数名区别开。
另一个是_data属性以一个下划线开始,这介于公共
属性(不以下划线开始)和私有属性之间(以两个下划线开始,参见第六章“类”)。
而Python的保留字在开始和结尾都有两个下划线。
这里的意思是:
_data是一个
属性,用户不应该直接访问,类的设计者希望这个“伪私有”属性只被类和子类
的方法使用。
定义新的列表和字典:
UserList和UserDict模块
前面展示的堆栈类作了恰当的工作。
它采取了关于堆栈的最小定义,只支持两个
操作:
push和pop。
然而,很快你就发现列表的特性确实好,比如可以用
for...in...的方式访问所有的成员。
这可以通过重用已有的代码来实现。
在这
里你应当应用UserList模块里定义的类UserList作为基类,堆栈由此派生而来。
库里也包括UserDict模块,它是一个封装字典的类。
一般来说,它们是用于特
别子类的基类。
#从UserList模块中导入UserList类
fromUserListimportUserList
#继承UserList类
classStack(UserList):
push=UserList.append
item=self[-1]#使用__getitem__
delself[-1]
这个堆栈是UserList的一个子类。
UserList类通过定义特别的__getitem__
和__delitem__方法实现了方括号的运算,所以前面代码里的pop能工作。
你
不必定义你自己的__init__方法,因为UserList已经定义了一个相当不错的。
最后只是说明push方法等于UserList的append方法。
现在我们可以用列表和
堆栈两种方式来操作了。
279
printthingsToDo#从UserList继承
washthekid'
thingsToDo.pop()
changetheoil'
forchoreinthingsToDo:
#我们也可以用"
for..in.."
遍历内容
...printchore#因为有__getitem__
writetomom
invitefriendover
changetheoil
注意:
当我们写这本书时,GuidovanRossom宣布在Python1.5.2(以及后续版本里),列表
对象将增加一个pop方法,它也有一个可选参数来指定pop的索引(缺省是列表最后的
一个成员)。
文件操作
脚本语言的设计目标之一是帮助人们快速而简单地做重复工作。
Web管理员,系
统管理员和程序员的经常需要做的一件事是:
从一个文件集合中选出一个子集,
对这个子集做某种操作,并把结果写到一个或一组输出文件中(例如,在某个目
录里的每个文件里,隔行查找以非#字符开头的行的最后一个词,并把它与文件
名一起打印出来)。
人们为这类任务已经设计了特定的工具,例如sed和awk。
我
们发现Python能很简单地完成这个工作。
操作一个文本文件里的每一行
当解析一个包含文本的输入文件时,sys模块是非常有用的。
在它的属性中有三
个文件对象,分别称为sys.stdin、sys.stdout和sys.stderr。
名字来源于三个
流的概念:
分别为标准输入、标准输出和标准错误。
它们与命令行工具有关,
print语句使用标准输出。
它是一个文件对象,具有以写模式打开的文件对象的
所有输出方法,如write和writelines。
另一个常用的流是标准输入(stdin),
它也是一个文件对象,不过它拥有的是输入方法,例如read、readline和
readlines。
下面的脚本会算出通过“管道”输入的文件行数:
280
importsys
data=sys.stdin.readlines()
print"
Counted"
len(data),"
lines."
在Unix上你可以做如下的测试:
%catcountlines.py|pythoncountlines.py
Counted3lines.
在Windows或DOS上,你可以:
C:
\>
typecountlines.py|pythoncountlines.py
当实现简单的过滤操作时,readlines函数是有用的。
这里有一些过滤操作的例
子:
寻找所有以#开始的行
forlineinsys.stdin.readlines():
ifline[0]=='
#'
printline,
注意print语句后的逗号是需要的,因为line字符串里已经有一个换行符。
取出一个文件的第四列(这里列是由空白符定义的)
importsys,string
words=string.split(line)
iflen(words)>
=4:
printwords[3]
我们通过words列表的长度判断是否确实至少有四个列,最后两行可以用
try/except惯用法代替,这在Python里是常见的:
try:
exceptIndexError:
#没有足够的列
pass
取出文件的第四列,列由冒号分开,并用小写输出
words=string.split(line,'
281
printstring.lower(words[3])
打印头10行,最后10行,并隔行打印输出
lines=sys.stdin.readlines()
sys.stdout.writelines(lines[:
10])
#头10行
sys.stdout.writelines(lines[-10:
#最后10行
forlineIndexinrange(0,len(lines),2):
#0,2,4,......
sys.stdout.write(lines[lineIndex])
#0,2,4,......行
计算单词“Python”在一个文件里出现的次数
importstring
text=open(fname).read()
printstring.count(text,'
Python'
把一个文件的列变换为一个列表的行
在这个比较复杂的例子里,任务是“转置”一个文件,设想你有这样一个文
件:
Name:
WillieMarkGuidoMaryRachelAhmed
Level:
543164
Tag#:
123444515515512418815132
而你希望它变成这样:
Level:
Tag#:
Willie51234
Mark44451
你可以用下面的代码:
wordlists=[]
forlineinlines:
wordlists.append(words)
forrowinrange(len(wordlists[0])):
forcolinrange(len(wordlists)):
printwordlists[col][row]+'
\t'
当然你应当用更多的防卫性编程技巧来处理一些可能的情况,比如也许不是
所有的行都有相同的单词数,也许丢失了数据等等。
这些就作为练习留给读
者。
282
选择数据块的大小
前面的所有例子都假设你能一次读入整个文件。
然而有时候这是不可能的,比如
在内存较小的计算机上处理大文件,或者处理不断地增加的文件(如日志文件)。
对这种情况你可以用一个while/readline组合,一次读入文件的一小部分直到
读完。
对于不是基于行的文本文件,你必须一次读入一个字符:
#逐字地读入
while1:
next=sys.stdin.read
(1)
#读入一个单字符串
ifnotnext:
#或者读到EOF时是空串
break
处理字符串'
next'
注意文件对象的read()方法在文件结尾时返回一个空串,并由此而跳出循环。
然
而更常见的是你将处理基于行的文本文件,并且一次处理一行:
#逐行地读入
next=sys.stdin.readline()
#读入一个单行字符串
处理行'
处理命令行上指定的一组文件
能够读stdin是一个
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- learnpython09