python编写工具 程序编写 新手问题

页面导航:
→ 正文内容 Python编程中规避一些bug的建议
对Python新手编程过程中如何规避一些常见问题的建议
这篇文章中作者对Python新手编程过程中如何规避一些常见问题给出了建议,主要着眼于初学者对于一些常用函数方法在平时的使用习惯中的问题给出建议,需要的朋友可以参考下
这篇文章收集了我在Python新手开发者写的代码中所见到的不规范但偶尔又很微妙的问题。本文的目的是为了帮助那些新手开发者渡过写出丑陋的Python代码的阶段。为了照顾目标读者,本文做了一些简化(例如:在讨论迭代器的时候忽略了生成器和强大的迭代工具itertools)。
对于那些新手开发者,总有一些使用反模式的理由,我已经尝试在可能的地方给出了这些理由。但通常这些反模式会造成代码缺乏可读性、更容易出bug且不符合。如果你想要寻找更多的相关介绍资料,我极力推荐或。
range的使用
Python编程新手喜欢使用range来实现简单的迭代,在迭代器的长度范围内来获取迭代器中的每一个元素:
for i in range(len(alist)):
print alist[i]
应该牢记:range并不是为了实现序列简单的迭代。相比那些用数字定义的for循环,虽然用range实现的for循环显得很自然,但是用在序列的迭代上却容易出bug,而且不如直接构造迭代器看上去清晰:
for item in alist:
print item
range的滥用容易造成意外的大小差一(off-by-one)错误,这通常是由于编程新手忘记了range生成的对象包括range的第一个参数而不包括第二个,类似于java中的和其他众多这种类型的函数。那些认为没有超出序列结尾的编程新手将会制造出bug:
# 迭代整个序列错误的方法
alist = ['her', 'name', 'is', 'rio']
for i in range(0, len(alist) - 1): # 大小差一(Off by one)!
print i, alist[i]
不恰当地使用range的常见理由:
1. 需要在循环中使用索引。这并不是一个合理的理由,可以用以下方式代替使用索引:
for index, value in enumerate(alist):
print index, value
2. 需要同时迭代两个循环,用同一个索引来获取两个值。这种情况下,可以用来实现:
for word, number in zip(words, numbers):
print word, number
3. 需要迭代序列的一部分。在这种情况下,仅需要迭代序列切片就可以实现,注意添加必要的注释注明用意:
for word in words[1:]: # 不包括第一个元素
print word
有一个例外:当你迭代一个很大的序列时,切片操作引起的开销就比较大。如果序列只有10个元素,就没有什么问题;但是如果有1000万个元素时,或者在一个性能敏感的内循环中进行切片操作时,开销就变得非常重要了。这种情况下可以考虑使用代替range [1]。
在用来迭代序列之外,range的一个重要用法是当你真正想要生成一个数字序列而不是用来生成索引:
# Print foo(x) for 0&=x&5
for x in range(5):
print foo(x)
正确使用列表解析
如果你有像这样的一个循环:
# An ugly, slow way to build a list
words = ['her', 'name', 'is', 'rio']
alist = []
for word in words:
alist.append(foo(word))
你可以使用列表解析来重写:
words = ['her', 'name', 'is', 'rio']
alist = [foo(word) for word in words]
为什么要这么做?一方面你避免了正确初始化列表可能带来的错误,另一方面,这样写代码让看起来很干净,整洁。对于那些有函数式编程背景的人来说,使用可能感觉更熟悉,但是在我看来这种做法不太Python化。
其他的一些不使用列表解析的常见理由:
1. 需要循环嵌套。这个时候你可以嵌套整个列表解析,或者在列表解析中多行使用循环:
words = ['her', 'name', 'is', 'rio']
letters = []
for word in words:
for letter in word:
letters.append(letter)
使用列表解析:
words = ['her', 'name', 'is', 'rio']
letters = [letter for word in words
for letter in word]
注意:在有多个循环的列表解析中,循环有同样的顺序就像你并没有使用列表解析一样。
2. 你在循环内部需要一个条件判断。你只需要把这个条件判断添加到列表解析中去:
words = ['her', 'name', 'is', 'rio', '1', '2', '3']
alpha_words = [word for word in words if isalpha(word)]
一个不使用列表解析的合理的理由是你在列表解析里不能使用异常处理。如果迭代中一些元素可能引起异常,你需要在列表解析中通过函数调用转移可能的异常处理,或者干脆不使用列表解析。
在线性时间内检查内容
在语法上,检查list或者set/dict中是否包含某个元素表面上看起来没什么区别,但是表面之下却是截然不同的。如果你需要重复检查某个数据结构里是否包含某个元素,最好使用set来代替list。(如果你想把一个值和要检查的元素联系起来,可以使用dict;这样同样可以实现常数检查时间。)
# 假设以list开始
lyrics_list = ['her', 'name', 'is', 'rio']
# 避免下面的写法
words = make_wordlist() # 假设返回许多要测试的单词
for word in words:
if word in lyrics_list: # 线性检查时间
print word, "is in the lyrics"
# 最好这么写
lyrics_set = set(lyrics_list) # 线性时间创建set
words = make_wordlist() # 假设返回许多要测试的单词
for word in words:
if word in lyrics_set: # 常数检查时间
print word, "is in the lyrics"
[译者注:Python中set的元素和dict的键值是可哈希的,因此查找起来时间复杂度为O(1)。
应该记住:创建set引入的是一次性开销,创建过程将花费线性时间即使成员检查花费常数时间。因此如果你需要在循环里检查成员,最好先花时间创建set,因为你只需要创建一次。
通常说来,在Python中,一个变量的作用域比你在其他语言里期望的要宽。例如:在Java中下面的代码将不能通过编译:
// Get the index of the lowest-indexed item in the array
// that is & maxValue
for(int i = 0; i & y. i++) {
if (y[i] & maxValue) {
// i在这里出现不合法:不存在i
processArray(y, i);
然而在Python中,同样的代码总会顺利执行且得到意料中的结果:
for idx, value in enumerate(y):
if value & max_value:
processList(y, idx)
这段代码将会正常运行,除非子y为空的情况下,此时,循环永远不会执行,而且processList函数的调用将会抛出NameError异常,因为idx没有定义。如果你使用Pylint代码检查工具,将会警告:使用可能没有定义的变量idx。
解决办法永远是显然的,可以在循环之前设置idx为一些特殊的值,这样你就知道如果循环永远没有执行的时候你将要寻找什么。这种模式叫做。那么什么值可以用来作为哨兵呢?在C语言时代或者更早,当int统治编程世界的时候,对于需要返回一个期望的错误结果的函数来说为通用的模式为返回-1。例如,当你想要返回列表中某一元素的索引值:
def find_item(item, alist):
# None比-1更加Python化
result = -1
for idx, other_item in enumerate(alist):
if other_item == item:
result = idx
return result
通常情况下,在Python里None是一个比较好的哨兵值,即使它不是一贯地被Python标准类型使用(例如:str.find [2])
Python程序员新手经常喜欢把所有东西放到所谓的外作用域――python文件中不被代码块(例如函数或者类)包含的部分。外作用域相当于全局命名空间;为了这部分的讨论,你应该假设全局作用域的内容在单个Python文件的任何地方都是可以访问的。
对于定义整个模块都需要去访问的在文件顶部声明的常量,外作用域显得非常强大。给外作用域中的任何变量使用有特色的名字是明智的做法,例如,使用IN_ALL_CAPS 这个常量名。 这将不容易造成如下bug:
import sys
# See the bug in the function declaration?
def print_file(filenam):
"""Print every line of a file."""
with open(filename) as input_file:
for line in input_file:
print line.strip()
if __name__ == "__main__":
filename = sys.argv[1]
print_file(filename)
如果你看的近一点,你将看到print_file函数的定义中用filenam命名参数名,但是函数体却引用的却是filename。然而,这个程序仍然可以运行得很好。为什么呢?在print_file函数里,当一个局部变量filename没有被找到时,下一步是在全局作用域中去寻找。由于print_file的调用在外作用域中(即使有缩进),这里声明的filename对于print_file函数是可见的。
那么如何避免这样的错误呢?首先,在外作用域中不是IN_ALL_CAPS这样的全局变量就不要设置任何值[3]。参数解析最好交给main函数,因此函数中任何内部变量不在外作用域中存活。
这也提醒人们关注全局关键字global。如果你只是读取全局变量的值,你就不需要全局关键字global。你只有在想要改变全局变量名引用的对象时有使用global关键字的必要。你可以在这里获取更多相关信息。
向PEP8致敬
是Python代码的通用风格指南,你应该牢记在心并且尽可能去遵循它,尽管一些人有充分的理由不同意其中一些细小的风格,例如缩进的空格个数或使用空行。如果你不遵循PEP8,你应该有除“我只是不喜欢那样的风格”之外更好的理由。下边的风格指南都是从PEP8中摘取的,似乎是编程者经常需要牢记的。
测试是否为空
如果你要检查一个容器类型(例如:列表,词典,集合)是否为空,只需要简单测试它而不是使用类似检查len(x)&0这样的方法:
numbers = [-1, -2, -3]
# This will be empty
positive_numbers = [num for num in numbers if num & 0]
if positive_numbers:
# Do something awesome
如果你想在其他地方保存positive_numbers是否为空的结果,可以使用bool(positive_number)作为结果保存;bool用来判断if条件判断语句的真值。
测试是否为None
如前面所提到,None可以作为一个很好的哨兵值。那么如何检查它呢?
如果你明确的想要测试None,而不只是测试其他一些值为False的项(如空容器或者0),可以使用:
if x is not None:
# Do something with x
如果你使用None作为哨兵,这也是Python风格所期望的模式,例如在你想要区分None和0的时候。
如果你只是测试变量是否为一些有用的值,一个简单的if模式通常就够用了:
# Do something with x
例如:如果期望x是一个容器类型,但是x可能作另一个函数的返回结果值变为None,你应该立即考虑到这种情况。你需要留意是否改变了传给x的值,否则可能你认为True或0. 0是个有用的值,程序却不会按照你想要的方式执行。
[1] 在Python2.x 中 range生成的是list对象,xrange生成的则是range对象;Python 3.x 废除了xrange,range生成的统一为range对象,用list工厂函数可以显式生成list;
[2] string.find(str)返回str在string中开始的索引值,如果不存在则返回-1;
[3] 在外作用于中不要给函数中的局部变量名设置任何值,以防止函数内部调用局部变量时发生错误而调用外部作用域中的同名变量。
您可能感兴趣的文章:
上一篇:下一篇:
最 近 更 新
热 点 排 行
12345678910当前位置: >
> webpy源码学习(一)自己是个python新手,之前买了本<<python核心编程&
webpy源码学习(一)自己是个python新手,之前买了本<<python核心编程&
xrzhai & at
webpy 源码学习(一)
自己是个python新手,之前买了本$$,但看了一半实在看不下去了(内容过于啰嗦,而且在关键点的地方又浅尝辄止),所以希望通过阅读一些简单的开源项目来快速提高python水平,最终让我发现了webpy这个好东西!
那么webpy是什么呢?&阅读它的源码我们又能学到什么呢?
简单说webpy就是一个开源的web应用框架(官方首页:)
它的源代码非常整洁精干,学习它一方面可以让我们快速了解python语法(遇到看不懂的语法就去google),另一方面可以学习到python的高级特性的使用(譬如装饰器),而且在webpy中还内置了一个简单HTTP服务器(文档建议该服务器仅用于开发环境,生产环境应使用apache之类的),对于想简单了解下HTTP服务器实现的朋友来说,这个是再好不过的例子了(并且在这个服务器代码中,还可以学习到线程池,消息队列等技术),除此之外webpy还包括模板渲染引擎,DB框架等等,这里面的每一个部分都可以单独拿出来学习.
在JavaWeb开发中有Servlet规范,那么Python&Web开发中有规范吗?
答案就是:WSGI,它定义了服务器如何与你的webapp交互
关于WSGI规范,可以参看下面这个链接:
现在我们利用webpy内置的WSGIServer,按照WSGI规范,写一个简单的webapp,eg:
  #/usr/bin/python
import&web.wsgiserver
def&my_wsgi_app(env,&start_response):
&&&&status&=&'200&OK'&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&response_headers&=&[('Content-type','text/plain')]
&&&&start_response(status,&response_headers)
&&&&return&['Hello&world!']
server&=&web.wsgiserver.CherryPyWSGIServer(("127.0.0.1",&8080),&my_wsgi_app);
server.start()
执行代码:
在具体看WSGIServer代码之前,我们先看一幅图,这幅图概述了WSGIServer内部执行流程:
接下来我们看下代码,ps:&为了较清晰的梳理主干流程,我只列出核心代码段
  #&Webpy内置的WSGIServer
class&CherryPyWSGIServer(HTTPServer):
&&&&def&__init__(self,&bind_addr,&wsgi_app,&numthreads=10,&server_name=None,
&&&&&&&&&&&&&&&&&max=-1,&request_queue_size=5,&timeout=10,&shutdown_timeout=5):
&&&&&&&&#&线程池(用来处理外部请求,稍后详述)
&&&&&&&&self.requests&=&ThreadPool(self,&min=numthreads&or&1,&max=max)
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&&&湘教QS2-164&&增值电信业务经营许可证湘B2-您现在的位置: >
大家都在 里讨论、交流,你还在等什么!赶快加入!
很多初学语言的人都会考虑,写Python程序最好用的编辑器是什么?但往往因为学习方法的不同,而选择了不同编辑器来使用。久而久之形成习惯,在新手阶段也无所谓好与坏了。随着对python语言的了解更加深入,和同行业朋友们之间交流越来越多,这时大多数人会知道更多、更好用、更漂亮的python编辑器并开始长时间使用。
下面就来说说从python入门到精通阶段,同学们感觉写Python程序最好用的编辑器有哪些?
初学者使用什么python编辑器好?在开始学习PYTHON语言的时候,无论是教科书或是老师都会告诉你,python提供了IDLE,它也有一个内置的代码编辑器,虽然它的功能不是很强大,但足可以满足入门新手的使用。。
还记得本人在学习python初期有短暂的使用过,后来发现了许多人推荐sublime,试用后感觉很顺手也就长时间的使用了。
感觉还不错的有同行业朋友推荐过的PyScripter,它支持Python2.4、2.5、2.6、2.7、3.0、3.1、3.2;再有一种很强大的Vim(Linux),开始用的时候可能会不太顺手,用久了感觉很好用。不只仅此而已,还有一些是面向专业python开发人员使用的python编辑器。
最好用的写Python程序编辑器是什么?并没有统一定义,因人而异,用着顺手就是最好用的。
玩蛇网原创,转载请注明文章出处和来源网址:
如果有任何Python编程相关问题,都可以加入玩蛇网的Python答疑QQ群: ①
文章发布日期: 17:05
我要分享到:
相关文章推荐
别人正在看
Python学习与资源分享平台

我要回帖

更多关于 python编写工具 的文章

 

随机推荐