欢迎来到天天爱彩票ios_天天爱彩票下载_天天爱彩票世界杯版本! 联系我们 网站地图

天天爱彩票ios_天天爱彩票下载_天天爱彩票世界杯版本

0379-65557469

天天爱彩票ios
全国服务热线
0379-65557469

电话: 0379-65557469
0379-63930906
0379-63900388 
0379-63253525   
传真: 0379-65557469
地址:洛阳市洛龙区开元大道219号2幢1-2522、2501、2502、2503、2504、2505室 

天天爱彩票ios
当前位置: 首页 | 咨询案例 > 天天爱彩票ios

程序员老司机都要错的 Python 圈套与缺点列表

作者:admin 发布时间:2019-11-29 21:24:07 浏览次数:185
打印 收藏 关闭
字体【
视力保护色


我个人对圈套的界说是这样的:代码看起来可以作业,但不是以你“想当然“”的方法。假如一段代码直接犯错,抛出了反常,我不以为这是圈套。比方,Python程序员应该都遇到过的“UnboundLocalError”, 示例:

>>> a=1>>> def func():... a+=1... print a...>>> func()Traceback (most recent call last):File "", line 1, in File "", line 2, in funcUnboundLocalError: local variable 'a' referenced before assignment


关于“UnboundLocalError”,还有更高档的版别:

import random def func(ok): if ok: a = random.random() else: import random a = random.randint(1, 10) return a func(True)# UnboundLocalError: local variable 'random' referenced before assignment


或许关于许多python新手来说,这个Error让人摸不着头脑。但我以为这不算圈套,由于这段代码必定会报错,而不是静静的以过错的方法运转。不怕真小人,就怕伪君子。我以为缺点就比方伪君子。

那么Python中哪些真实算得上圈套呢?

榜首:以mutable目标作为默许参数

这个估量是最广为人知的了,Python和其他许多言语相同,供给了默许参数,默许参数的确是个好东西,可以让函数调用者疏忽一些细节(比方GUI编程,Tkinter,QT),关于lambda表达式也十分有用。可是假如运用了可变目标作为默许参数,那么作业就不那么愉快了。

>>> def f(lst = []):... lst.append(1)... return lst...>>> f()[1]>>> f()[1, 1]


惊喜不惊喜?!究其原因,python中一切都是目标,函数也不列外,默许参数仅仅函数的一个特点。而默许参数在函数界说的时分现已求值了。

Default parameter values are evaluated when the function definition is executed.


stackoverflow上有一个更恰当的比方来阐明默许参数是在界说的时分求值,而不是调用的时分。

>>> import time>>> def report(when=time.time()):... return when...>>> report()1500113234.487932>>> report()1500113234.487932


python docoment 给出了规范的解决办法:

A way around this is to use None as the default, and explicitly test for it in the body of the function


>>> def report(when=None):... 程序员老司机都要错的 Python 圈套与缺点列表if when is None:... when = time.time()... return when...>>> report()1500113446.746997>>> report()1500113448.552873


第二: x += y vs x = x + y

一般来说,二者是等价的,至少看起来是等价的(这也是圈套的界说 — 看起来都OK,但不必定正确)。

>>> x=1;x += 1;print x2 >>> x=1;x = x+1;print x2>>> x=[1];x+=[2];print x[1, 2]>>> x=[1];x=x+[2];print x[1, 2]


呃,被光速打脸了?

>>> x=[1];print id(x);x=x+[2];print id(x) 43571328004357132728>>> x=[1];print id(x);x+=[2];print id(x)43571328004357132800


前者x指向一个新的目标,后者x在本来的目标是修正,当然,那种作用是正确的取决于运用场景。至少,得知道,二者有时分并不相同

第三,奇特的小括号–()

小括号(parenthese)在各种编程言语中都有广泛的运用,python中,小括号还能表明元组(tuple)这一数据类型, 元组是immutable的序列。

>>> a = (1, 2)>>> type(a)>>> type(())


但假如只要一个元素呢

>>> 夏普a=(1)>>> type(a)


奇特不奇特,假如要表明只要一个元素的元组,正确的姿态是:

>>> a=(1,)>>> type(a)


第四:生成一个元素是列表的列表

这个有点像二维数组,当然生成一个元素是字典的列表也是可以的,更浅显的说,生成一个元素是可变目标的序列

很简略嘛:

>>> a= [[]] * 10>>> a[[], [], [], [], [], [], [], [], [], []]>>> a[0].append(10)>>> a[0] 程序员老司机都要错的 Python 圈套与缺点列表[10]


看起来很不错,简略明了,but

>>> a[1][10]>>> a[[10], [10], [10], [10], [10], [10], [10], [10], [10], [10]]


我猜,这应该不是你预期的成果吧,究其原因,仍是由于python中list是可变目标,上述的写法我们都指向的同一个可变目标,正确的姿态

>>> a = [[] for _ in xrange(10)]>>> a[0].append(10)>>> a[[10], [], [], [], [], [], [], [], [], []]


第五,在拜访列表的时分,修正列表

列表(list)在python中运用十分广泛,当然常常会在拜访列表的时分添加或许删去一些元素。比方,下面这个函数,企图删掉列表中为3的倍数的元素:

>>> def modify_lst(lst):... for idx, elem in enumerate(lst):... if elem % 3 == 0:... del lst[idx]


测验一下,

>>> lst = [1,2,3,4,5,6]>>> modify_lst(lst)>>> lst[1, 2, 4, 5]


如同没什么错,不过这仅仅命运好

>>> lst = [1,2,3,6,5,4]>>> modify_lst(lst)>>> lst[1, 2, 6, 5, 4]


上面的比方中,6这个元素就没有被删去。假如在modify_lst函数中print idx, item就可以发现端倪:lst在变短,但idx是递加的,所以在上面犯错的比方中,当3被删去之后,6变成了lst的第2个元素(从0开端)。在C++中,假如遍历容器的时分用迭代器删去元素,也会有相同的问题。

假如逻辑比较简略,运用list comprehension是不错的留意

第六,闭包与lambda

这个也是老生长谈的比方,在其他言语也有相似的状况。先看一个比方:

>>> def create_multipliers():... return [lambda x:i*x for i in range(5)]...>>> for multiplier in create_multipliers():... print multiplier(2)...


create_multipliers函数的回来值时一个列表,列表的每一个元素都是一个函数 -- 将输入参数x乘以一个倍数i的函数。预期的成果时0,2,4,6,8. 但成果是5个8,意外不意外。

由于呈现这个圈套的时分常常运用了lambda,所以或许会以为是lambda的问题,但lambda表明不愿意背这个锅。问题的实质在与python中的特点查找规矩,LEGB(local,enclousin程序员老司机都要错的 Python 圈套与缺点列表g,global,bulitin),在上面的比方中,i便是在闭包作用域(enclousing),而Python的闭包是 迟绑定 , 这意味着闭包中用到的变量的值,是在内部函数被调用时查询得到的。

解决办法也很简略,那便是变闭包作用域为部分作用域。

>>> def create_multipliers():... return [lambda x, i = i:i*x for i in range(5)]...


第七,界说__del__

大多数计算机专业的同学或许都是先学的C、C++,结构、析构函数的概念应该都十分熟。所以,当切换到python的时分,天然也想知道有没有相应的函数。比方,在C++中十分有名的RAII,即经过结构、析构来办理资源(如内存、文件描绘符)的声明周期。那在python中要到达相同的作用怎么做呢,即需求找到一个目标在毁掉的时分必定会调用的函数,所以发现了__init__, __del__函数,或许简略写了两个比方发现的确也能作业。但事实上或许掉进了一个圈套,在python documnet是有描绘的:

Circular references which are garbage are detected when the option cycle detector is enabled (it’s on by default), but can only be cleaned up if there are no Python-level __del__() methods involved.


简略来说,假如在循环引证中的目标界说了__del__,那么python gc不能进行收回,因而,存在内存走漏的危险

第八,不同的姿态import同一个module

示例在stackoverflow的比方上稍作修正,假定现在有一个package叫mypackage,里边包括三个python文件:mymodule.py, main.py, __init__.py。mymodule.py代码如下:

l = []class A(object): pass


main.py代码如下:

def add(x): from mypackage import mymodule mymodule.l.append(x) print "updated list",mymodule.l, id(mymodule) def get(): import mymodule print 'module in get', id(mymodule) return mymodule.l if __name__ == '__main__': import sys sys.path.append('../') add(1) ret = get() print "lets check", ret


运转python main.py,成果如下:

updated list [1] 4406700752module in get 4406700920lets check []


从运转成果可以看到,在add 和 get函数中import的mymodule不是同一个module,ID不同。当然,在python2.7.10中,需求main.py的第13行才干呈现这样的作用。你或许会问,谁会写出第13行这样的代码呢?事实上,在许多项目中,为了import的时分便利,会往sys.path参加一堆途径。那么在项目中,我们赞同一种import方法就十分有必要了

第九,python晋级

python3.x并不向后兼容,所以假如从2.x晋级到3.x的时分得当心了,下面罗列两点:

在python2.7中,range的回来值是一个列表;而在python3.x中,回来的是一个range目标。

map()、filter()、 dict.items()在python2.7回来列表,而在3.x中回来迭代器。当然迭代器大多数都是比较好的挑选,愈加pythonic,可是也有缺点,便是只能遍历一次。在instagram的共享中,也说到由于这个导致的一个坑爹的bug。

第十,gil

以GIL结束,由于gil是Python中我们公认的缺点!

从其他言语过来的同学或许看到python用threading模块,拿过来就用,成果发现作用不对啊,然后就会喷,什么鬼。

总结:

毫无疑问的说,python是十分简单上手,也十分强壮的一门言语。python十分灵敏,可定制化很强。一起,也存在一些圈套,搞清楚这些圈套可以更好的把握、运用这么言语。本文罗列了一些python中的一些缺点,这是一份不完全列表,欢迎我们弥补。

来历作者:xybaby

来历链接:www.cnblogs.com/xybaby/p/7183854.html

版权所有:洛阳市建设工程咨询有限责任公司 联系人:李经理 电话: 地址:洛阳市洛龙区开元大道219号2幢1-2522、2501、2502、2503、2504、2505室
版权所有 天天爱彩票ios 沪ICP备112423759号-9