怎么用python 引用其他文件对于文件之间的差异

Python程序员的常见错误 - 博客 - 伯乐在线
& Python程序员的常见错误
& 7.4K 阅读
译注: 是《Learning Python | 》的作者之一。
在这篇文章中,我将总结新老Python程序员常犯的一些错误,以帮助你们在自己的工作避免犯同样或类似错误。
首先我要说明一下的是,这些都是来源于第一手的经验。我以讲授Python的知识为生。在过去的7年里,我已经给上千名学生讲授上百堂Python的课程,同时看着这些学生们犯同样的错。也就是说,这些是我看着Python初学者活生生犯的错,千百次的错。事实上,这些错误实在是太普遍了以至于我敢保证你刚开始学的时候是一定会犯的。
“那么是什么呢?”你会问,“你也会在Python里犯那么多错么?”是的。Python可能是最简单、最灵活的语言之一,但它终究还是一门编程语言。它仍然有语法,数据类型,以及巫师蒂姆居住的黑暗角落。
(典故出自《蒙蒂派森与圣杯》中的魔法师蒂姆,他主角们指点在洞穴的墙壁上记录的圣杯位置,作者在此处的意思是Python语言里容易犯错的地方。另,Python语言得名于作者Guido van Rossum特别喜欢的《蒙蒂派森飞行马戏团(Monty Python’s Flying Circus)》——译者注)
好事情是多亏了Python那干净的设计,一旦你学会了Python,你就能自动的避开很多陷阱。Python在其各组件之间有着最小的互动,这能有效的减少bug。它也拥有十分简单的语法,这意味着在一开始你就有更小的概率犯错。当你实在是犯了错的时候,Python的即时错误检测和报告能帮你迅速的恢复。
但用Python编程也不是个自动完成的活儿,很多事还是要早做准备。那么废话不多说了,让我们直切正题。在接下来的三节里我们将这些错误分为语用、代码,以及编程三个大类。如果你想读到更多的Python的常见错误以及如何避免它们,那么在O’Reilly系列丛书的《Learning Python》里有详细的解读。(译注:Learning Python 已经是第五版了)
让我们从基础开始,从那些刚学习编程的人钻研语法之前碰到的事情开始。如果你已经编过一些程了,那么以下这些可能看起来十分的简单;如果你曾经尝试过教新手们怎么编程,它们可能就不这么简单了。
在交互提示符中输入Python代码
在&&&交互提示符中你只能输入Python代码,而不是系统命令。时常有人在这个提示符下输入emacs,ls,或者edit之类的命令,这些可不是Python代码。在Python代码中确实有办法来调用系统命令(例如os.system和os.popen),但可不是像直接输入命令这么直接。如果你想要在交互提示符中启动一个Python文件,请用import file,而不是系统命令python file.py。
Print语句(仅仅)是在文件中需要
因为交互解释器会自动的讲表达式的结果输出,所以你不需要交互的键入完整的print语句。这是个很棒的功能,但是记住在代码文件里,通常你只有用print语句才能看得到输出。
小心Windows里的自动扩展名
如果你在Windows里使用记事本来编辑代码文件的话,当你保持的时候小心选择“所有文件”(All Files)这个类型,并且明确的给你的文件加一个.py的后缀。不然的话记事本会给你的文件加一个.txt的扩展名,使得在某些启动方法中没法跑这个程序。更糟糕的是,像Word或者是写字板一类的文字处理软件还会默认的加上一些格式字符,而这些字符Python语法是不认的。所以记得,在Windows下总是选“所有文件”(All Files),并保存为纯文本,或者使用更加“编程友好”的文本编辑工具,比如IDLE。在IDLE中,记得在保存时手动加上.py的扩展名。
在Windows下点击图标的问题
在Windows下,你能靠点击Python文件来启动一个Python程序,但这有时会有问题。首先,程序的输出窗口在程序结束的瞬间也就消失了,要让它不消失,你可以在文件最后加一条raw_input()的调用。另外,记住如果有错的话,输出窗口也就立即消失了。要看到你的错误信息的话,用别的方法来调用你的程序:比如从系统命令行启动,通过提示符下用import语句,或者IDLE菜单里的选项,等等。
Import只在第一次有效
你可以在交互提示符中通过import一个文件来运行它,但是这只会在一个会话中起一次作用;接下来的import仅仅是返回这个已经加载的模块。要想强制Python重新加载一个文件的代码,请调用函数reload(module)来达到这个目的。注意对reload请使用括号,而import不要使用括号。
空白行(仅仅)在交互提示符中有作用
在模块文件中空白行和注释统统会被忽略掉,但是在交互提示符中键入代码时,空白行表示一个复合语句的结束。换句话说,空白行告诉交互提示符你完成了一个复合语句;在你真正完成之前不要键入回车。事实上当你要开始一个新的语句时,你需要键入一个空行来结束当前的语句——交互提示符一次只运行一条语句。
一旦你开始认真写Python代码了,接下来了一堆陷阱就更加危险了——这些都是一些跨语言特性的基本代码错误,并常常困扰不细心的程序员。
别忘了冒号
这是新手程序员最容易犯的一个错误:别忘了在复合语句的起始语句(if,while, for等语句的第一行)结束的地方加上一个冒号“:”。也许你刚开始会忘掉这个,但是到了很快这就会成为一个下意识的习惯。课堂里75%的学生当天就可以记住这个。
初始化变量
在Python里,一个表达式中的名字在它被赋值之前是没法使用的。这是有意而为的:这样能避免一些输入失误,同时也能避免默认究竟应该是什么类型的问题(0,None,””,[],?)。记住把计数器初始化为0,列表初始化为[],以此类推。
从第一列开始
确保把顶层的,未嵌套的代码放在最左边第一列开始。这包括在模块文件中未嵌套的代码,以及在交互提示符中未嵌套的代码。Python使用缩进的办法来区分嵌套的代码段,因此在你代码左边的空格意味着嵌套的代码块。除了缩进以外,空格通常是被忽略掉的。
在同一个代码块中避免讲tab和空格混用来缩进,除非你知道运行你的代码的系统是怎么处理tab的。否则的话,在你的编辑器里看起来是tab的缩进也许Python看起来就会被视作是一些空格。保险起见,在每个代码块中全都是用tab或者全都是用空格来缩进;用多少由你决定。
在函数调用时使用括号
无论一个函数是否需要参数,你必须要加一对括号来调用它。即,使用function(),而不是function。Python的函数简单来说是具有特殊功能(调用)的对象,而调用是用括号来触发的。像所有的对象一样,他们也可以被赋值给变量,并且间接的使用他们:x=function:x()。
在Python的培训中,这样的错误常常在文件的操作中出现。通常会看到新手用file.close来关闭一个问题,而不是用file.close()。因为在Python中引用一个函数而不调用它是合法的,因此不使用括号的操作(file.close)无声的成功了,但是并没有关闭这个文件!
在Import时不要使用表达式或者路径
在系统的命令行里使用文件夹路径或者文件的扩展名,但不要在import语句中使用。即,使用import mod,而不是import mod.py,或者import dir/mod.py。在实际情况中,这大概是初学者常犯的第二大错误了。因为模块会有除了.py以为的其他的后缀(例如,.pyc),强制写上某个后缀不仅是不合语法的,也没有什么意义。
和系统有关的目录路径的格式是从你的模块搜索路径的设置里来的,而不是import语句。你可以在文件名里使用点来指向包的子目录(例如,import dir1.dir2.mod),但是最左边的目录必须得通过模块搜索路径能够找到,并且没有在import中没有其他路径格式。不正确的语句import mod.py被Python认为是要记在一个包,它先加载一个模块mod,然后试图通过在一个叫做mod的目录里去找到叫做py的模块,最后可能什么也找不到而报出一系列费解的错误信息。
不要在Python中写C代码
以下是给不熟悉Python的C程序员的一些备忘贴士:
在if和while中条件测试时,不用输入括号(例如,if (X==1):)。如果你喜欢的话,加上括号也无妨,只是在这里是完全多余的。
不要用分号来结束你的语句。从技术上讲这在Python里是合法的,但是这毫无用处,除非你要把很多语句放在同一行里(例如,x=1; y=2; z=3)。
不要在while循环的条件测试中嵌入赋值语句(例如,while ((x=next() != NULL))。在Python中,需要表达式的地方不能出现语句,并且赋值语句不是一个表达式。
下面终于要讲到当你用到更多的Python的功能(数据类型,函数,模块,类等等)时可能碰到的问题了。由于篇幅有限,这里尽量精简,尤其是对一些高级的概念。要想了解更多的细节,敬请阅读Learning Python, 2nd Edition的“小贴士”以及“Gotchas”章节。
打开文件的调用不使用模块搜索路径
当你在Python中调用open()来访问一个外部的文件时,Python不会使用模块搜索路径来定位这个目标文件。它会使用你提供的绝对路径,或者假定这个文件是在当前工作目录中。模块搜索路径仅仅为模块加载服务的。
不同的类型对应的方法也不同
列表的方法是不能用在字符串上的,反之亦然。通常情况下,方法的调用是和数据类型有关的,但是内部函数通常在很多类型上都可以使用。举个例子来说,列表的reverse方法仅仅对列表有用,但是len函数对任何具有长度的对象都适用
不能直接改变不可变数据类型
记住你没法直接的改变一个不可变的对象(例如,元组,字符串):
T = (1, 2, 3)
用切片,联接等构建一个新的对象,并根据需求将原来变量的值赋给它。因为Python会自动回收没有用的内存,因此这没有看起来那么浪费:
T = T[:2] + (4,)
# 没问题了: T 变成了 (1, 2, 4)
使用简单的for循环而不是while或者range
当你要从左到右遍历一个有序的对象的所有元素时,用简单的for循环(例如,for x in seq:)相比于基于while-或者range-的计数循环而言会更容易写,通常运行起来也更快。除非你一定需要,尽量避免在一个for循环里使用range:让Python来替你解决标号的问题。在下面的例子中三个循环结构都没有问题,但是第一个通常来说更好;在Python里,简单至上。
S = &lumberjack&
for c in S: print c
for i in range(len(S)): print S[i]
while i & len(S): print S[i]; i += 1
不要试图从那些会改变对象的函数得到结果
诸如像方法list.append()和list.sort()一类的直接改变操作会改变一个对象,但不会将它们改变的对象返回出来(它们会返回None);正确的做法是直接调用它们而不要将结果赋值。经常会看见初学者会写诸如此类的代码:
mylist = mylist.append(X)
目的是要得到append的结果,但是事实上这样做会将None赋值给mylist,而不是改变后的列表。更加特别的一个例子是想通过用排序后的键值来遍历一个字典里的各个元素,请看下面的例子:
for k in D.keys().sort(): print D[k]
差一点儿就成功了——keys方法会创建一个keys的列表,然后用sort方法来将这个列表排序——但是因为sort方法会返回None,这个循环会失败,因为它实际上是要遍历None(这可不是一个序列)。要改正这段代码,将方法的调用分离出来,放在不同的语句中,如下:
Ks = D.keys()
for k in Ks: print D[k]
只有在数字类型中才存在类型转换
在Python中,一个诸如123+3.145的表达式是可以工作的——它会自动将整数型转换为浮点型,然后用浮点运算。但是下面的代码就会出错了:
# 类型错误
这同样也是有意而为的,因为这是不明确的:究竟是将字符串转换为数字(进行相加)呢,还是将数字转换为字符串(进行联接)呢?在Python中,我们认为“明确比含糊好”(即,EIBTI(Explicit is better than implicit)),因此你得手动转换类型:
X = int(S) + I
# 做加法: 43
X = S + str(I)
# 字符串联接: &421&
循环的数据结构会导致循环
尽管这在实际情况中很少见,但是如果一个对象的集合包含了到它自己的引用,这被称为循环对象(cyclic object)。如果在一个对象中发现一个循环,Python会输出一个[…],以避免在无限循环中卡住:
&&& L = ['grail']
# 在 L中又引用L自身会
&&& L.append(L)
# 在对象中创造一个循环
['grail', [...]]
除了知道这三个点在对象中表示循环以外,这个例子也是很值得借鉴的。因为你可能无意间在你的代码中出现这样的循环的结构而导致你的代码出错。如果有必要的话,维护一个列表或者字典来表示已经访问过的对象,然后通过检查它来确认你是否碰到了循环。
赋值语句不会创建对象的副本,仅仅创建引用
这是Python的一个核心理念,有时候当行为不对时会带来错误。在下面的例子中,一个列表对象被赋给了名为L的变量,然后L又在列表M中被引用。内部改变L的话,同时也会改变M所引用的对象,因为它们俩都指向同一个对象。
&&& L = [1, 2, 3]
# 共用的列表对象
&&& M = ['X', L, 'Y']
# 嵌入一个到L的引用
['X', [1, 2, 3], 'Y']
&&& L[1] = 0
# 也改变了M
['X', [1, 0, 3], 'Y']
通常情况下只有在稍大一点的程序里这就显得很重要了,而且这些共用的引用通常确实是你需要的。如果不是的话,你可以明确的给他们创建一个副本来避免共用的引用;对于列表来说,你可以通过使用一个空列表的切片来创建一个顶层的副本:
&&& L = [1, 2, 3]
&&& M = ['X', L[:], 'Y']
# 嵌入一个L的副本
&&& L[1] = 0
# 仅仅改变了L,但是不影响M
['X', [1, 2, 3], 'Y']
切片的范围起始从默认的0到被切片的序列的最大长度。如果两者都省略掉了,那么切片会抽取该序列中的所有元素,并创造一个顶层的副本(一个新的,不被公用的对象)。对于字典来说,使用字典的dict.copy()方法。
静态识别本地域的变量名
Python默认将一个函数中赋值的变量名视作是本地域的,它们存在于该函数的作用域中并且仅仅在函数运行的时候才存在。从技术上讲,Python是在编译def代码时,去静态的识别本地变量,而不是在运行时碰到赋值的时候才识别到的。如果不理解这点的话,会引起人们的误解。比如,看看下面的例子,当你在一个引用之后给一个变量赋值会怎么样:
&&& X = 99
&&& def func():
# 这个时候还不存在
# 在整个def中将X视作本地变量
&&& func( )
# 出错了!
你会得到一个“未定义变量名”的错误,但是其原因是很微妙的。当编译这则代码时,Python碰到给X赋值的语句时认为在这个函数中的任何地方X会被视作一个本地变量名。但是之后当真正运行这个函数时,执行print语句的时候,赋值语句还没有发生,这样Python便会报告一个“未定义变量名”的错误。
事实上,之前的这个例子想要做的事情是很模糊的:你是想要先输出那个全局的X,然后创建一个本地的X呢,还是说这是个程序的错误?如果你真的是想要输出这个全局的X,你需要将它在一个全局语句中声明它,或者通过包络模块的名字来引用它。
默认参数和可变对象
在执行def语句时,默认参数的值只被解析并保存一次,而不是每次在调用函数的时候。这通常是你想要的那样,但是因为默认值需要在每次调用时都保持同样对象,你在试图改变可变的默认值(mutable defaults)的时候可要小心了。例如,下面的函数中使用一个空的列表作为默认值,然后在之后每一次函数调用的时候改变它的值:
&&& def saver(x=[]):
# 保存一个列表对象
x.append(1)
# 并每次调用的时候
# 改变它的值
&&& saver([2])
# 未使用默认值
&&& saver()
# 使用默认值
&&& saver()
# 每次调用都会增加!
&&& saver()
有的人将这个视作Python的一个特点——因为可变的默认参数在每次函数调用时保持了它们的状态,它们能提供像C语言中静态本地函数变量的类似的一些功能。但是,当你第一次碰到它时会觉得这很奇怪,并且在Python中有更加简单的办法来在不同的调用之间保存状态(比如说类)。
要摆脱这样的行为,在函数开始的地方用切片或者方法来创建默认参数的副本,或者将默认值的表达式移到函数里面;只要每次函数调用时这些值在函数里,就会每次都得到一个新的对象:
&&& def saver(x=None):
if x is None: x = []
# 没有传入参数?
x.append(1)
# 改变新的列表
&&& saver([2])
# 没有使用默认值
&&& saver()
# 这次不会变了
&&& saver()
其他常见的编程陷阱
下面列举了其他的一些在这里没法详述的陷阱:
在顶层文件中语句的顺序是有讲究的:因为运行或者加载一个文件会从上到下运行它的语句,所以请确保将你未嵌套的函数调用或者类的调用放在函数或者类的定义之后。
reload不影响用from加载的名字:reload最好和import语句一起使用。如果你使用from语句,记得在reload之后重新运行一遍from,否则你仍然使用之前老的名字。
在多重继承中混合的顺序是有讲究的:这是因为对superclass的搜索是从左到右的,在类定义的头部,在多重superclass中如果出现重复的名字,则以最左边的类名为准。
在try语句中空的except子句可能会比你预想的捕捉到更多的错误。在try语句中空的except子句表示捕捉所有的错误,即便是真正的程序错误,和sys.exit()调用,也会被捕捉到。
兔子可能会比他们看起来更加危险。(原句Bunnies can be more dangerous than they seem. 意思是一些看起来比较细微的问题实际上可能更危险。——译者注)
作者系世界领先的Python教育者,Python最早的畅销教材的作者,并且从1992年开始便长期贡献于Python社区。
关于作者:
兔子很危险这个梗是不是也来自《蒙蒂派森与圣杯》
为作者带来更多读者;为读者筛选优质内容;专注IT互联网。
最新评论(期待您也参与评论)
汇集优质的Python技术文章和资源。人生苦短,我用Python!
JavaScript, CSS, HTML5 这里有前端的技术干货!
关注安卓移动开发业界动态,分享技术文章和优秀工具资源。
关注iOS移动开发业界动态,分享技术文章和优秀工具资源。
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线博客团队正试图以我们微薄的力量,把优秀的原创/译文分享给读者,做一个小而精的精选博客,为“快餐”添加一些“营养”元素。
欢迎关注更多频道
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选博客文章
– JavaScript, HTML5, CSS
– 专注Android技术分享
– 专注iOS技术分享
– 专注Java技术分享
– 专注Python技术分享
(加好友请注明来意)
网站使用问题
请在询问或者反馈
& 2015 伯乐在线
赞助云主机Python 使用__import__不能导入不同目录下的*.python文件
[问题点数:100分,结帖人testhu]
Python 使用__import__不能导入不同目录下的*.python文件
[问题点数:100分,结帖人testhu]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
2014年8月 其他开发语言大版内专家分月排行榜第二2014年7月 其他开发语言大版内专家分月排行榜第二2014年5月 其他开发语言大版内专家分月排行榜第二2014年4月 其他开发语言大版内专家分月排行榜第二2014年3月 其他开发语言大版内专家分月排行榜第二2014年1月 其他开发语言大版内专家分月排行榜第二2013年12月 其他开发语言大版内专家分月排行榜第二2013年11月 其他开发语言大版内专家分月排行榜第二2013年3月 其他开发语言大版内专家分月排行榜第二2012年5月 其他开发语言大版内专家分月排行榜第二2012年4月 其他开发语言大版内专家分月排行榜第二2010年10月 其他开发语言大版内专家分月排行榜第二2010年9月 其他开发语言大版内专家分月排行榜第二
2013年9月 其他开发语言大版内专家分月排行榜第三2012年6月 其他开发语言大版内专家分月排行榜第三
2006年5月 PHP大版内专家分月排行榜第二2006年4月 PHP大版内专家分月排行榜第二2007年1月 PHP大版内专家分月排行榜第二
2013年10月 其他开发语言大版内专家分月排行榜第三2007年2月 PHP大版内专家分月排行榜第三
2014年8月 其他开发语言大版内专家分月排行榜第二2014年7月 其他开发语言大版内专家分月排行榜第二2014年5月 其他开发语言大版内专家分月排行榜第二2014年4月 其他开发语言大版内专家分月排行榜第二2014年3月 其他开发语言大版内专家分月排行榜第二2014年1月 其他开发语言大版内专家分月排行榜第二2013年12月 其他开发语言大版内专家分月排行榜第二2013年11月 其他开发语言大版内专家分月排行榜第二2013年3月 其他开发语言大版内专家分月排行榜第二2012年5月 其他开发语言大版内专家分月排行榜第二2012年4月 其他开发语言大版内专家分月排行榜第二2010年10月 其他开发语言大版内专家分月排行榜第二2010年9月 其他开发语言大版内专家分月排行榜第二
2013年9月 其他开发语言大版内专家分月排行榜第三2012年6月 其他开发语言大版内专家分月排行榜第三
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。出处: 译注:
是《Learning Python |
》的作者之一。
在这篇文章中,我将总结新老Python程序员常犯的一些错误,以帮助你们在自己的工作避免犯同样或类似错误。
首先我要说明一下的是,这些都是来源于第一手的经验。我以讲授Python的知识为生。在过去的7年里,我已经给上千名学生讲授上百堂Python的课程,同时看着这些学生们犯同样的错。也就是说,这些是我看着Python初学者活生生犯的错,千百次的错。事实上,这些错误实在是太普遍了以至于我敢保证你刚开始学的时候是一定会犯的。
“那么是什么呢?”你会问,“你也会在Python里犯那么多错么?”是的。Python可能是最简单、最灵活的语言之一,但它终究还是一门编程语言。它仍然有语法,数据类型,以及巫师蒂姆居住的黑暗角落。
(典故出自《蒙蒂派森与圣杯》中的魔法师蒂姆,他主角们指点在洞穴的墙壁上记录的圣杯位置,作者在此处的意思是Python语言里容易犯错的地方。另,Python语言得名于作者Guido van Rossum特别喜欢的《蒙蒂派森飞行马戏团(Monty Python’s Flying Circus)》——译者注)
好事情是多亏了Python那干净的设计,一旦你学会了Python,你就能自动的避开很多陷阱。Python在其各组件之间有着最小的互动,这能有效的减少bug。它也拥有十分简单的语法,这意味着在一开始你就有更小的概率犯错。当你实在是犯了错的时候,Python的即时错误检测和报告能帮你迅速的恢复。
但用Python编程也不是个自动完成的活儿,很多事还是要早做准备。那么废话不多说了,让我们直切正题。在接下来的三节里我们将这些错误分为语用、代码,以及编程三个大类。如果你想读到更多的Python的常见错误以及如何避免它们,那么在O’Reilly系列丛书的《Learning Python》里有详细的解读。(译注:Learning Python 已经是第五版了)
让我们从基础开始,从那些刚学习编程的人钻研语法之前碰到的事情开始。如果你已经编过一些程了,那么以下这些可能看起来十分的简单;如果你曾经尝试过教新手们怎么编程,它们可能就不这么简单了。
在交互提示符中输入Python代码
在&&&交互提示符中你只能输入Python代码,而不是系统命令。时常有人在这个提示符下输入emacs,ls,或者edit之类的命令,这些可不是Python代码。在Python代码中确实有办法来调用系统命令(例如os.system和os.popen),但可不是像直接输入命令这么直接。如果你想要在交互提示符中启动一个Python文件,请用import file,而不是系统命令python file.py。
Print语句(仅仅)是在文件中需要
因为交互解释器会自动的讲表达式的结果输出,所以你不需要交互的键入完整的print语句。这是个很棒的功能,但是记住在代码文件里,通常你只有用print语句才能看得到输出。
小心Windows里的自动扩展名
如果你在Windows里使用记事本来编辑代码文件的话,当你保持的时候小心选择“所有文件”(All Files)这个类型,并且明确的给你的文件加一个.py的后缀。不然的话记事本会给你的文件加一个.txt的扩展名,使得在某些启动方法中没法跑这个程序。更糟糕的是,像Word或者是写字板一类的文字处理软件还会默认的加上一些格式字符,而这些字符Python语法是不认的。所以记得,在Windows下总是选“所有文件”(All Files),并保存为纯文本,或者使用更加“编程友好”的文本编辑工具,比如IDLE。在IDLE中,记得在保存时手动加上.py的扩展名。
在Windows下点击图标的问题
在Windows下,你能靠点击Python文件来启动一个Python程序,但这有时会有问题。首先,程序的输出窗口在程序结束的瞬间也就消失了,要让它不消失,你可以在文件最后加一条raw_input()的调用。另外,记住如果有错的话,输出窗口也就立即消失了。要看到你的错误信息的话,用别的方法来调用你的程序:比如从系统命令行启动,通过提示符下用import语句,或者IDLE菜单里的选项,等等。
Import只在第一次有效
你可以在交互提示符中通过import一个文件来运行它,但是这只会在一个会话中起一次作用;接下来的import仅仅是返回这个已经加载的模块。要想强制Python重新加载一个文件的代码,请调用函数reload(module)来达到这个目的。注意对reload请使用括号,而import不要使用括号。
空白行(仅仅)在交互提示符中有作用
在模块文件中空白行和注释统统会被忽略掉,但是在交互提示符中键入代码时,空白行表示一个复合语句的结束。换句话说,空白行告诉交互提示符你完成了一个复合语句;在你真正完成之前不要键入回车。事实上当你要开始一个新的语句时,你需要键入一个空行来结束当前的语句——交互提示符一次只运行一条语句。
一旦你开始认真写Python代码了,接下来了一堆陷阱就更加危险了——这些都是一些跨语言特性的基本代码错误,并常常困扰不细心的程序员。
别忘了冒号
这是新手程序员最容易犯的一个错误:别忘了在复合语句的起始语句(if,while, for等语句的第一行)结束的地方加上一个冒号“:”。也许你刚开始会忘掉这个,但是到了很快这就会成为一个下意识的习惯。课堂里75%的学生当天就可以记住这个。
初始化变量
在Python里,一个表达式中的名字在它被赋值之前是没法使用的。这是有意而为的:这样能避免一些输入失误,同时也能避免默认究竟应该是什么类型的问题(0,None,””,[],?)。记住把计数器初始化为0,列表初始化为[],以此类推。
从第一列开始
确保把顶层的,未嵌套的代码放在最左边第一列开始。这包括在模块文件中未嵌套的代码,以及在交互提示符中未嵌套的代码。Python使用缩进的办法来区分嵌套的代码段,因此在你代码左边的空格意味着嵌套的代码块。除了缩进以外,空格通常是被忽略掉的。
在同一个代码块中避免讲tab和空格混用来缩进,除非你知道运行你的代码的系统是怎么处理tab的。否则的话,在你的编辑器里看起来是tab的缩进也许Python看起来就会被视作是一些空格。保险起见,在每个代码块中全都是用tab或者全都是用空格来缩进;用多少由你决定。
在函数调用时使用括号
无论一个函数是否需要参数,你必须要加一对括号来调用它。即,使用function(),而不是function。Python的函数简单来说是具有特殊功能(调用)的对象,而调用是用括号来触发的。像所有的对象一样,他们也可以被赋值给变量,并且间接的使用他们:x=function:x()。
在Python的培训中,这样的错误常常在文件的操作中出现。通常会看到新手用file.close来关闭一个问题,而不是用file.close()。因为在Python中引用一个函数而不调用它是合法的,因此不使用括号的操作(file.close)无声的成功了,但是并没有关闭这个文件!
在Import时不要使用表达式或者路径
在系统的命令行里使用文件夹路径或者文件的扩展名,但不要在import语句中使用。即,使用import mod,而不是import mod.py,或者import dir/mod.py。在实际情况中,这大概是初学者常犯的第二大错误了。因为模块会有除了.py以为的其他的后缀(例如,.pyc),强制写上某个后缀不仅是不合语法的,也没有什么意义。
和系统有关的目录路径的格式是从你的模块搜索路径的设置里来的,而不是import语句。你可以在文件名里使用点来指向包的子目录(例如,import dir1.dir2.mod),但是最左边的目录必须得通过模块搜索路径能够找到,并且没有在import中没有其他路径格式。不正确的语句import mod.py被Python认为是要记在一个包,它先加载一个模块mod,然后试图通过在一个叫做mod的目录里去找到叫做py的模块,最后可能什么也找不到而报出一系列费解的错误信息。
不要在Python中写C代码
以下是给不熟悉Python的C程序员的一些备忘贴士:
在if和while中条件测试时,不用输入括号(例如,if (X==1):)。如果你喜欢的话,加上括号也无妨,只是在这里是完全多余的。
不要用分号来结束你的语句。从技术上讲这在Python里是合法的,但是这毫无用处,除非你要把很多语句放在同一行里(例如,x=1; y=2; z=3)。
不要在while循环的条件测试中嵌入赋值语句(例如,
while ((x=next() != NULL))。在Python中,需要表达式的地方不能出现语句,并且赋值语句不是一个表达式。
下面终于要讲到当你用到更多的Python的功能(数据类型,函数,模块,类等等)时可能碰到的问题了。由于篇幅有限,这里尽量精简,尤其是对一些高级的概念。要想了解更多的细节,敬请阅读Learning Python, 2
nd Edition的“小贴士”以及“Gotchas”章节。
打开文件的调用不使用模块搜索路径
当你在Python中调用open()来访问一个外部的文件时,Python不会使用模块搜索路径来定位这个目标文件。它会使用你提供的绝对路径,或者假定这个文件是在当前工作目录中。模块搜索路径仅仅为模块加载服务的。
不同的类型对应的方法也不同
列表的方法是不能用在字符串上的,反之亦然。通常情况下,方法的调用是和数据类型有关的,但是内部函数通常在很多类型上都可以使用。举个例子来说,列表的reverse方法仅仅对列表有用,但是len函数对任何具有长度的对象都适用
不能直接改变不可变数据类型
记住你没法直接的改变一个不可变的对象(例如,元组,字符串):
T = (1, 2, 3)
用切片,联接等构建一个新的对象,并根据需求将原来变量的值赋给它。因为Python会自动回收没有用的内存,因此这没有看起来那么浪费:
T = T[:2] + (4,)
# 没问题了: T 变成了 (1, 2, 4)
使用简单的for循环而不是while或者range
当你要从左到右遍历一个有序的对象的所有元素时,用简单的for循环(例如,
for x in seq:)相比于基于while-或者range-的计数循环而言会更容易写,通常运行起来也更快。除非你一定需要,尽量避免在一个for循环里使用range:让Python来替你解决标号的问题。在下面的例子中三个循环结构都没有问题,但是第一个通常来说更好;在Python里,简单至上。
S = &lumberjack&
for c in S: print c
for i in range(len(S)): print S[i]
while i & len(S): print S[i]; i += 1
不要试图从那些会改变对象的函数得到结果
诸如像方法list.append()和list.sort()一类的直接改变操作会改变一个对象,但不会将它们改变的对象返回出来(它们会返回None);正确的做法是直接调用它们而不要将结果赋值。经常会看见初学者会写诸如此类的代码:
mylist = mylist.append(X)
目的是要得到append的结果,但是事实上这样做会将None赋值给mylist,而不是改变后的列表。更加特别的一个例子是想通过用排序后的键值来遍历一个字典里的各个元素,请看下面的例子:
for k in D.keys().sort(): print D[k]
差一点儿就成功了——keys方法会创建一个keys的列表,然后用sort方法来将这个列表排序——但是因为sort方法会返回None,这个循环会失败,因为它实际上是要遍历None(这可不是一个序列)。要改正这段代码,将方法的调用分离出来,放在不同的语句中,如下:
Ks = D.keys()
for k in Ks: print D[k]
只有在数字类型中才存在类型转换
在Python中,一个诸如123+3.145的表达式是可以工作的——它会自动将整数型转换为浮点型,然后用浮点运算。但是下面的代码就会出错了:
# 类型错误
这同样也是有意而为的,因为这是不明确的:究竟是将字符串转换为数字(进行相加)呢,还是将数字转换为字符串(进行联接)呢?在Python中,我们认为“明确比含糊好”(即,EIBTI(Explicit is better than implicit)),因此你得手动转换类型:
X = int(S) + I
# 做加法: 43
X = S + str(I)
# 字符串联接: &421&
循环的数据结构会导致循环
尽管这在实际情况中很少见,但是如果一个对象的集合包含了到它自己的引用,这被称为
循环对象(cyclic object)。如果在一个对象中发现一个循环,Python会输出一个[…],以避免在无限循环中卡住:
&&& L = [&grail&]
# 在 L中又引用L自身会
&&& L.append(L)
# 在对象中创造一个循环
[&grail&, [...]]
除了知道这三个点在对象中表示循环以外,这个例子也是很值得借鉴的。因为你可能无意间在你的代码中出现这样的循环的结构而导致你的代码出错。如果有必要的话,维护一个列表或者字典来表示已经访问过的对象,然后通过检查它来确认你是否碰到了循环。
赋值语句不会创建对象的副本,仅仅创建引用
这是Python的一个核心理念,有时候当行为不对时会带来错误。在下面的例子中,一个列表对象被赋给了名为L的变量,然后L又在列表M中被引用。内部改变L的话,同时也会改变M所引用的对象,因为它们俩都指向同一个对象。
&&& L = [1, 2, 3]
# 共用的列表对象
&&& M = [&X&, L, &Y&]
# 嵌入一个到L的引用
[&X&, [1, 2, 3], &Y&]
&&& L[1] = 0
# 也改变了M
[&X&, [1, 0, 3], &Y&]
通常情况下只有在稍大一点的程序里这就显得很重要了,而且这些共用的引用通常确实是你需要的。如果不是的话,你可以明确的给他们创建一个副本来避免共用的引用;对于列表来说,你可以通过使用一个空列表的切片来创建一个顶层的副本:
&&& L = [1, 2, 3]
&&& M = [&X&, L[:], &Y&]
# 嵌入一个L的副本
&&& L[1] = 0
# 仅仅改变了L,但是不影响M
[&X&, [1, 2, 3], &Y&]
切片的范围起始从默认的0到被切片的序列的最大长度。如果两者都省略掉了,那么切片会抽取该序列中的所有元素,并创造一个顶层的副本(一个新的,不被公用的对象)。对于字典来说,使用字典的dict.copy()方法。
静态识别本地域的变量名
Python默认将一个函数中赋值的变量名视作是本地域的,它们存在于该函数的作用域中并且仅仅在函数运行的时候才存在。从技术上讲,Python是在编译def代码时,去静态的识别本地变量,而不是在运行时碰到赋值的时候才识别到的。如果不理解这点的话,会引起人们的误解。比如,看看下面的例子,当你在一个引用之后给一个变量赋值会怎么样:
&&& X = 99
&&& def func():
# 这个时候还不存在
# 在整个def中将X视作本地变量
&&& func( )
# 出错了!
你会得到一个“未定义变量名”的错误,但是其原因是很微妙的。当编译这则代码时,Python碰到给X赋值的语句时认为在这个函数中的任何地方X会被视作一个本地变量名。但是之后当真正运行这个函数时,执行print语句的时候,赋值语句还没有发生,这样Python便会报告一个“未定义变量名”的错误。
事实上,之前的这个例子想要做的事情是很模糊的:你是想要先输出那个全局的X,然后创建一个本地的X呢,还是说这是个程序的错误?如果你真的是想要输出这个全局的X,你需要将它在一个全局语句中声明它,或者通过包络模块的名字来引用它。
默认参数和可变对象
在执行def语句时,默认参数的值只被解析并保存一次,而不是每次在调用函数的时候。这通常是你想要的那样,但是因为默认值需要在每次调用时都保持同样对象,你在试图改变可变的默认值(mutable defaults)的时候可要小心了。例如,下面的函数中使用一个空的列表作为默认值,然后在之后每一次函数调用的时候改变它的值:
&&& def saver(x=[]):
# 保存一个列表对象
x.append(1)
# 并每次调用的时候
# 改变它的值
&&& saver([2])
# 未使用默认值
&&& saver()
# 使用默认值
&&& saver()
# 每次调用都会增加!
&&& saver()
有的人将这个视作Python的一个特点——因为可变的默认参数在每次函数调用时保持了它们的状态,它们能提供像C语言中静态本地函数变量的类似的一些功能。但是,当你第一次碰到它时会觉得这很奇怪,并且在Python中有更加简单的办法来在不同的调用之间保存状态(比如说类)。
要摆脱这样的行为,在函数开始的地方用切片或者方法来创建默认参数的副本,或者将默认值的表达式移到函数里面;只要每次函数调用时这些值在函数里,就会每次都得到一个新的对象:
&&& def saver(x=None):
if x is None: x = []
# 没有传入参数?
x.append(1)
# 改变新的列表
&&& saver([2])
# 没有使用默认值
&&& saver()
# 这次不会变了
&&& saver()
其他常见的编程陷阱
下面列举了其他的一些在这里没法详述的陷阱:
在顶层文件中语句的顺序是有讲究的:因为运行或者加载一个文件会从上到下运行它的语句,所以请确保将你未嵌套的函数调用或者类的调用放在函数或者类的定义之后。
reload不影响用from加载的名字:reload最好和import语句一起使用。如果你使用from语句,记得在reload之后重新运行一遍from,否则你仍然使用之前老的名字。
在多重继承中混合的顺序是有讲究的:这是因为对superclass的搜索是从左到右的,在类定义的头部,在多重superclass中如果出现重复的名字,则以最左边的类名为准。
在try语句中空的except子句可能会比你预想的捕捉到更多的错误。在try语句中空的except子句表示捕捉所有的错误,即便是真正的程序错误,和sys.exit()调用,也会被捕捉到。
兔子可能会比他们看起来更加危险。(原句Bunnies can be more dangerous than they seem. 意思是一些看起来比较细微的问题实际上可能更危险。——译者注)
系世界领先的Python教育者,Python最早的畅销教材的作者,并且从1992年开始便长期贡献于Python社区。
。相关 [mark lutz python] 推荐:
- 博客 - 伯乐在线
Mark Lutz 是《Learning Python |
学习Python》的作者之一. 在这篇文章中,我将总结新老Python程序员常犯的一些错误,以帮助你们在自己的工作避免犯同样或类似错误. 首先我要说明一下的是,这些都是来源于第一手的经验. 我以讲授Python的知识为生. 在过去的7年里,我已经给上千名学生讲授上百堂Python的课程,同时看着这些学生们犯同样的错. 也就是说,这些是我看着Python初学者活生生犯的错,千百次的错. 事实上,这些错误实在是太普遍了以至于我敢保证你刚开始学的时候是一定会犯的. ”你会问,“你也会在Python里犯那么多错么. Python可能是最简单、最灵活的语言之一,但它终究还是一门编程语言.
- tiger - 36氪
近日,著名风险投资机构GRP的合伙人Mark Suster在一次公开演讲中以这样的表述开头:“虽然我很久没有这样说过了,但是这次我可以很负责任的说——我们已经身处泡沫中了. 随后他继续说到:“如果你在Cleveland或者Ohio,你可能不会有很深的感觉,但是在硅谷,纽约和洛杉矶,以往通常要花上3到5个月才能完成的融资现在花上3到5天就能完成. 在这样的背景下,Suster敦促其他还未进行融资的创业公司赶紧去融资,以便泡沫破灭的时候他们能够挺过寒冬. 他说:“到时聚会(指泡沫)结束,它就是真的结束了,所以开胃菜上上来的时候,不仅记得要吃上两块,还要藏起一块带回家吃. 由于经历过以往的3次周期,因而Suster非常明白聚会会以怎样的形式落幕(大部分创业公司都会被卷入悲剧),所以他在此希望传递自己从中学到的最大的经验,那就是备好粮草准备过冬.
- jianpx - 语虚
我们可以对文本进行标记,以方便在文档的不同位置间跳转. 将光标移到某一行,使用ma命令进行标记. 其中,m是标记命令,a是所做标记的名称. 可以使用小写字母a-z或大写字母A-Z中的任意一个做为标记名称. 小写字母的标记,仅用于当前缓冲区;而大写字母的标记,则可以跨越不同的缓冲区. 例如,你正在编辑File1,但仍然可以使用&A命令,移动到File2中创建的标记A. 创建标记后,可以使用&a命令,移动到指定标记行的首个非空字符. 也可以使用`a命令,移到所做标记时的光标位置. 这里`是反引号(也就是数字键1左边的那一个). 利用:marks命令,可以列出所有标记. 这其中也包括一些系统内置的特殊标记(Special marks):.
- chuang - Initiative
dropbox定制优化CPython虚拟机,自己搞了个malloc调度算法. 那个 !!!111cos(0). 期待这次PyCon China 2011.
- 企业架构 - ITeye博客
原文地址: http://blog.csdn.net/xuyuefei1988/article/details/、下面网上收罗的资料初学者应该够用了,但对比IBM的Python 代码调试技巧:. IBM:包括 pdb 模块、利用 PyDev 和 Eclipse 集成进行调试、PyCharm 以及 Debug 日志进行调试:. 2、另一份来自百度文库的《python日志输出----logging浅析与使用》比较全面,也受益匪浅,自己刚开始学手头没东西做,希望自己接下来能用上:. 3、使用gdb调试python脚本. (Pdb) 会自动停在第一行,等待调试,这时你可以看看 帮助.
- Eric - python相关的python 教程和python 下载你可以在老王python里寻觅
之前给大家分享的python 多线程抓取网页,我觉的大家看了以后,应该会对python 抓取网页有个很好的认识,不过这个只能用python 来抓取到网页的源代码,如果你想用做python 下载文件的话,上面的可能就不适合你了,最近我在用python 做文件下载的时候就遇到这个问题了,不过最终得以解决,为了让大家以后碰过这个问题有更好的解决办法,我把代码发出来:. download(r&你要下载的python文件的url地址&). 赶快去试试把,可以在本地运行python去下载一些自己想要的pdf文件吧. 继续阅读《python 下载文件》的全文内容.... 分类: python练习题 | Tags: python
python 下载
| 添加评论(4).
- 互联网 - ITeye博客
@FileName:
@Author:xx@
@Create date:
@description:用一行文字概述模块或脚本,用句号结尾. 不影响编码的效率,不与大众习惯冲突.. 使代码的逻辑更清晰,更易于理解..
*所有的 Python 脚本文件都应在文件头标上如下标识或其兼容格式的标识.
*设置编辑器,默认保存为 utf-8 格式.
*不论什么情况使用 UTF-8 吧.
# -*- coding:utf-8 -*-
#coding=utf-8.
一致的命名可以给开发人员减少许多麻烦,而恰如其分的命名则可以大幅提高代码的可读性,降低维护成本..
- 阿里古古
http://blog.csdn.net/luckeryin/article/details/4477233】. 本文讨论在没有方便的IDE工具可用的情况下,使用pdb调试python程序. 例如,有模拟税收计算的程序:. debug_demo函数计算4500的入账所需的税收. 在需要插入断点的地方,加入红色部分代码:如果_DEBUG值为True,则在该处开始调试(加入_DEBUG的原因是为了方便打开/关闭调试).
运行程序./debug_demo.py,得到. -& val &= 1600 : 指示当前执行的语句,(Pdb)等待你的调试指令. pdb的指令很丰富,输入h指令可以查看指令的使用方法.
- wdestinyx - Engadget 中国版
鼠标发展到现在还有拓展空间么. 继续阅读全文 佳能X Mark I,给你的鼠标加上计算器. 此文章网址 | 转寄此文章 | 回应.
- 刘星炜 - 谷奥——探寻谷歌的奥秘
Larry Page 和 Sergey Brin 尴尬了,根据统计网站
的数字,现在在 Google+ 上人气第一的用户不是别人,正是 Facebook 的小马哥. 小马哥的 Follower 已经有 21,213 人,而 Google 的两位创始人的 Follower 只有不到15000. Google+ Statistics 的创建者 Boris Veldhujizen van Zanten 解释说:小马哥有世界上最多的好友,他们甚至为小马哥拍了个电影. 另外他也比 Larry 和 Sergey 更帅. 另外,谷奥也以1968个 Follower 名列排行榜第39位.
坚持分享优质有趣的原创文章,并保留作者信息和版权声明,任何问题请联系:@。

我要回帖

更多关于 python 写文件 的文章

 

随机推荐