给Python初学者的一些编程发起
Python是一种很是富有表示力的语言。它为我们提供了一个复杂的尺度库和很多内置模块,辅佐我们快速完成事情。然而,很多人大概会迷失在它提供的成果中,不能充实操作尺度库,太过重视单行剧本,以及误解Python根基布局等。本文是一个关于Python新手大概会陷入的一些陷阱的不完全列表。
1.不知道Python版本
这是一个在StackOverflow上重复呈现的问题。很多人能写出在某个版本上完美事情的代码,但在他们在本身的系统上安装有差异版本的Python。要确保你知道你正在利用的Python版本。
你可以通过下边的代码查察Python版本:
[[email protected]]$ python --version Python 2.7.10 [[email protected]]$ python --V Python 2.7.10
上面两种要领都是可以的
2.不利用版本打点器
pyenv是一个极好的打点差异Python版本的东西,但很不幸,它只事情在*nix系统上。在Mac系统上,你可以简朴地通过brew install pyenv安装它,在Linux上,也有一个自动安装措施。
3.着迷于一行措施
很多人热衷于一行措施带来的欢快感。纵然他们的一行办理方案比一个多行办理方案低效,他们也会吹捧。
Python中的一行措施在本质上意味着具有多个表达式的巨大推导。譬喻:
l = [m for a, b in zip(this, that) if b.method(a) != b for m in b if not m.method(a, b) and reduce(lambda x, y: a + y.method(), (m, a, b))]
诚恳讲,我编造了上面的例子。但我看到许多人都写雷同的代码。这样的代码在一个礼拜后就会变得难以领略。假如你想做一些稍微巨大的工作,譬喻按照条件简朴地在一个列表或荟萃中添加一个元素,你大概就会出错误。
单行代码并不是什么成绩,是的,他们大概看起来很机动,但不是什么成绩。想象一下,这就像是你在拂拭房间时把所有的对象都塞进你的衣橱。好的代码应该是清洁的,易于阅读的和高效的。
4.操作错误的方法初始化一个荟萃
这是一个更微妙的问题,大概让你措手不及。荟萃推导很像列表推导。
>>> { n for n in range(10) if n % 2 == 0 } {0, 8, 2, 4, 6} >>> type({ n for n in range(10) if n % 2 == 0 })
上面就是荟萃推导的一个例子。荟萃就像列表,也是一个容器。所差异的是,一个荟萃中不能有任何反复的值,并且是无序的。看到荟萃推导人们常常错误地认为{}能初始化一个空荟萃。但其实否则,它初始化一个空字典。
>>> {} {} >>> type({})
假如你想初始化一个空荟萃,可以简朴地挪用set()要领。
>>> set() set() >>> type(set())
留意一个空集适用set()暗示,可是一个包括一些元素的荟萃就就要用花括号困绕元素来暗示。
>>> s = set() >>> s set() >>> s.add(1) >>> s {1} >>> s.add(2) >>> s {1, 2}
这和直觉是相反的,因为你期望雷同于set([1, 2])的一些对象。
5.误解GIL
GIL(全局表明器锁)意味着在Python措施中,任意一个时间点只能有一个线程在运行。这意味着当我们建设一个线程并但愿它并行运行时,它并不会那样。Python表明器实际的事情是在差异的运行线程之间快速举办切换。但这只是对实际产生工作的一个很是简朴的表明,实际环境要巨大的多。有许多种并行运行的实例,譬喻利用本质为C扩展的各类库。但运行Python代码时,大部门时间里它不会并行执行。换句话说,Python中的线程并不像Java或C++中的线程。
很多人会实验为Python辩解,说这些都是真正的线程。这确实是真的,但并不能改变这样一个事实:Python处理惩罚线程的方法和你期望的方法是差异的。Ruby语言也有沟通的环境(Ruby也有一个表明器锁)。
指定的办理方案是利用multiprocessing模块。multiprocessing模块提供Process类,它是一个对fork的很好的包围。然而,fork进程比一个线程的价钱高得多,所以你大概不会每次都能看到机能上的晋升,因为差异的process之间需要做大量的事情来举办彼此协调。
然而,这个问题并不存在于每一个Python的实现版本中。譬喻,Python的一个实现PyPy-stm就试图挣脱GIL(仍未不变)。成立在其他平台,如JVM(Jython)或CLR(IronPython),上的Python实现,也没有GIL的问题。
总之,利用Thread类时要多加小心,你获得的大概不是你想要的。
6.利用旧式类
#p#分页标题#e#
在Python 2中,有两种范例的类,别离为“旧式”类和“新式”类。假如你利用Python 3,那么你默认利用“新式”类。为了确保在Python2中利用“新式”类,你需要让你新建设的每一个类都担任object类,且类不能已担任了内置范例,譬喻int或list。换句话说,你的基类、类假如不担任其他类,就老是需要担任object类。
class MyNewObject(object): # stuff here
这些“新式”类办理一些老式类的基础缺陷,想要具体相识新式类和旧式类请拜见《python新式类和旧式类区别》《python2中的__new__与__init__,新式类和经典类》。
7.按错误的方法迭代
对付这门语言的新手来说,下边的代码长短经常见的:
for name_index in range(len(names)): print(names[name_index])
在上边的例子中,没有必需挪用len函数,因为列表迭代实际上要简朴得多:
for name in names: print(name)
另外,尚有一大堆其他的东西辅佐你简化迭代。譬喻,可以利用zip同时遍历两个列表:
for cat, dog in zip(cats, dogs): print(cat, dog)
假如你想同时思量列表变量的索引和值,可以利用enumerate:
for index, cat in enumerate(cats): print(cat, index)
在itertools中也有许多有用的函数供你选择。然而请留意,利用itertools函数并不老是正确的选择。假如itertools中的一个函数为你试图办理的问题提供了一个很是利便的办理步伐,譬喻铺平一个列表或按照给定的列表建设一个其内容的分列,那就用它吧。可是不要仅仅因为你想要它而去适应你代码的一部门。
滥用itertools激发的问题呈现的过于频繁,以至于在StackOverflow上一个德高望重的Python孝敬者已经孝敬他们资料的重要构成部门来办理这些问题。
8.利用可变的默认参数
我多次见到过如下的代码:
def foo(a, b, c=[]): # append to c # do some more stuff
永远不要利用可变的默认参数,可以利用如下的代码取代:
def foo(a, b, c=None): if c is None: c = [] # append to c # do some more stuff
与其表明这个问题是什么,不如展示下利用可变默认参数的影响:
>>> def foo(a, b, c=[]): ... c.append(a) ... c.append(b) ... print(c) ... >>> foo(1, 1) [1, 1] >>> foo(1, 1) [1, 1, 1, 1] >>> foo(1, 1) [1, 1, 1, 1, 1, 1]
同一个变量c在函数挪用的每一次都被重复引用。这大概有一些意想不到的效果。
总结
这些只是相对来说刚打仗Python的人大概会碰着的一些问题。然而请留意,大概会碰着的问题远非就这么些。然而另一些缺陷是人们像利用Java或C++一样利用Python,而且试图按他们熟悉的方法利用Python。