python的一些误区

原文连接放在这里:1: http://nafiulis.me/potential-pythonic-pitfalls.html
不少问题没搞懂,先放在这里,慢慢改。
python是一门很是有趣的语言。它提供了许多很是方便的标准库和许多内置命令是咱们轻松完成任务.可是好东西太多了就有选择恐惧症了,以致于咱们不能很好第利用这个标准库和它的基本机构。下面列出了一些对python新手来讲很简单有效的陷阱。html


忽略了python的版本

这是一个在StackOverflow上不断被人提起的问题。当你完美的代码跑在别人的电脑上就报错是怎样一种体验,因此这个时候就须要检查大家的python版本是否一致。确保代码跑在本身知道的python版本上。你能够经过如下代码查看python版本:python

$ python --version
Python 2.7.9

python版本管理

pyenv是一个不错的python版本管理工具。不幸的是它只运行在*nix系统上。在Mac OS上,你能够简单用brew install pyenv安装,在linux系统中,有一个自动安装器automatic installerlinux

纠结于用一行代码解决全部问题

许多人夸口说我多牛用一行代码就解决了全部问题,即使他们的代码比正常写的更缺乏效率,并且这些代码也会更难以阅读,甚至会出现歧义。好比说:c++

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))]

老实说上面的代码是我本身为了说明这件事情写的。可是我但是真的见过有许多人这样干过。若是你只是简单经过把东西添加到一个list或者一个set中来显摆本身解决复杂问题的手段,那么你有可能会得不偿失。git

一行代码控并非什么巨大的成就,尽管有时候看起来特别聪明。优秀的代码是简洁可是更注重高效和易读。github

错误地初始化set

这是一个更加微妙的问题,有时候会让你措手不及。set推导式起来有点像list推导式.app

>>> { 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 })
<class 'set'>

上面的例子说明了这点。set有点像放在容器中的list
它们的区别是set没有重复的值和无序的。人们一般会把{}认为是一个空的set,可它不是,它是一个空的dict.函数

>>> {}
{}
>>> type({})
<class 'dict'>

因此若是咱们想要初始化一个空的set,就直接使用set()工具

>>> set()
set()
>>> type(set())
<class 'set'>

注意一个空的set能够表示成set(),可是一个包含了元素的集合要被定义成set([1, 2])的样子。this


误解了GIL

GIL(全局解释器锁)意味着只有一个线程在一个Python程序能够运行在任什么时候间。 这意味着当咱们不能建立一个线程,并指望它并行运行。 Python解释器实际上作的是快速切换不一样的运行线程。 但这是一个很是简单的版本。 在许多实例中程序并行运行,像使用C扩展的库时。 但Python代码运行时,大多数时候不会并行执行。换句话说,线程在Python中不像在Java或c++中同样。

许多人会尝试为Python辩解说,这些都是真正的线程。 3 这确实是真的,但并不能改变这样一个事实:Python处理线程的方式不一样于你指望的那样。 Ruby也有相似的状况(还有一个解释器锁)。

规定的解决方案是使用multiprocessing模块。multiprocessing模块提供的过程类基本上能够很好地覆盖分歧。 然而,分歧比线程代价高得多。因此并行运行不老是好的。

然而,这个问题不是每一个Python程序都会遇到。PyPy-stm就是Python的一个实现不受GIL影响的例子。 实现创建在其余平台上的像JVM(Jython) 或CLR(IronPython)没有GIL的问题。

总之,在使用时要当心线程类,你获得的可能不是你想要的。

使用过期的样式类

在Python 2有两种类型的类,“旧式”类,“新风格”类。 若是 你使用Python 3,那么你正在使用默认的“新风格”类。 为了确保你使用 “新风格”在Python 2类,您须要继承object或者任何你建立的不老是继承内建指令intlist的新类 。 换句话说,你的基类,应该老是继承object

class MyNewObject(object):
    # stuff here

这些'新类'修复了一些很是基本的出如今老式类中问题,若是你感兴趣能够查看文档

错误的迭代

下面的这些错误对新手来讲很是常见:

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滥用使得StackOverflow上的一个大神花了不少时间去解决它。

使用了可变的默认参数

我看过不少以下:

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

下面这个例子能够很直观地帮咱们理解这个问题:

In[2]: def foo(a, b, c=[]):
...     c.append(a)
...     c.append(b)
...     print(c)
...
In[3]: foo(1, 1)
[1, 1]
In[4]: foo(1, 1)
[1, 1, 1, 1]
In[5]: foo(1, 1)
[1, 1, 1, 1, 1, 1]

相同的 c 被引用一次又一次的每一次调用该函数。 这可能会产生一些很是 没必要要的后果。

相关文章
相关标签/搜索