大多数Python开发人员都有不同的核心编程语言背景,例如java、C#或c++。因此,他们习惯于以艰难的方式做事,当他们以易于学习的Python语言介绍他们时,他们误解了Python的多功能性和功能,并且常常以误导自己而失去其一些微妙之处而告终。在本文中,我将尝试解决Python程序员遇到的错误。这些错误,甚至本文中的大部分错误,都是针对中级甚至专家级开发人员的。想知道?如果您是初学者或中级开发人员,请继续阅读文章Python开发人员常犯的10个最常见的错误,因为当前文章是为更高级的读者准备的。1.遍历列表的同时修改列表这是每个Python开发者一生中至少会面临一次的问题。查看以下代码片段中的问题:>>>odd=lambdax:bool(x%2)>>>numbers=[nforninrange(10)]>>>foriinrange(len(numbers)):...ifodd(numbers[i]):...delnumbers[i]#Deleteitemsinthelistwhileiteratedoverthelist...Traceback(mostrecentcalallast):File"",line2,inIndexError:listindexoutofrange这个问题很明显,但即使是高级开发人员在复杂的工作流程中添加代码时也会犯类似的错误。有几种解决方案。我想在这里讨论一个最佳解决方案,但根据我的说法,这是最简单的,所以我不太可能犯错。我建议列表理解在这种情况下非常有用。查看上面的代码以了解列表理解的实现:>>>odd=lambdax:bool(x%2)>>>numbers=[nforninrange(10)]>>>numbers[:]=[nforninnumbersifnotodd(n)]>>>numbers[0,2,4,6,8]2.创建一个循环模块依赖假设你有两个文件a.py和b.py,每个都导入另一个,像这样:在一个.py中:importbdeff():returnb.xprintf()Inb.py:importax=1defg():printa.f()首先,让我们尝试导入a.py:>>>importa1一切正常,没有错误。它应该给你一个错误,但这里的问题是,如果存在循环依赖,你有时可以逃脱它,因为python足够聪明,可以跟踪导入的包。当每个模块试图访问另一个模块的功能时,就会出现问题,因为不会声明另一个模块,这将导致像这样的AttributeError:>>>importbTraceback(mostrecentcalllast):File"",line1,inFile"b.py",line1,inimportaFile"a.py",line6,inprintf()File"a.py",line4,infreturnb.xAttributeError:'module'对象有noattribute'x'为了解决这个问题,我们需要在函数中导入其他依赖模块:x=1defg():importa#willonlybeevaluatedwheng()iscalledprinta.f()现在一切都应该正常工作:>>>importb>>>b.g()1#Firstprintsincemodule'a'called'printf()'attheend1#Secondprint,thisisourcallto'g'3.Errorusingexpressionasfunction默认值对于参数这是最难调试的错误之一,因为它不会给你一个错误,而且大部分时间它都能正常工作,开发人员可以侥幸逃脱。当我们可以指定一个可变的可选函数参数时,就会发生这种情况。例如:>>>deffoo(bar=[]):...bar.append("baz")...returnbar看起来我们已经创建了一个函数,它将baz附加到分配给它的列表结束,否则每次调用它时不带bar参数,它都会返回["baz"],因为bar将被初始化为[]。但是,当我们执行它时,我们得到以下结果:>>>foo()["baz"]>>>foo()["baz","baz"]>>>foo()["baz","baz","baz"]输出不符合预期,现在您将看到大多数开发人员如何在没有人注意到的情况下逃脱惩罚。看代码,很难找到没遇到过这个问题或者不知道Python是怎么计算函数的,因为每次都把bar的值初始化为[],很难。但在Python中,默认参数仅被评估一次,因此在第一次调用时它按预期工作,但在第二次和第三次调用时它使用现有的柱列表而不是评估它的初始化。下面是我们如何解决这个问题:>>>deffoo(bar=None):...ifbarisNone:#orifnotbar:...bar=[]...bar.append("baz")...returnbar...>>>foo()["baz"]>>>foo()["baz"]>>>foo()["baz"]4.类变量的误用请考虑以下示例:>>>classA(object):...x=1...>>>classB(A):...pass...>>>classC(A):...pass...>>>printA.x,B.x,C.x111这是有道理的。>>>B.x=2>>>printA.x,B.x,C.x121再次如预期>>>A.x=3>>>printA.x,B.x,C.x323什么?奇怪的是,通过更改A类的值,C类不受影响。这是因为在Python中,类变量在内部作为字典处理,并遵循称为“方法解析顺序”的顺序。发生这种情况是因为在类C中找不到属性x,因此在基类A中查找它。5.为异常块指定不正确的参数对于给定的代码:>>>try:...l=["a","b"]...int(l[2])...exceptValueError,IndexError:#Tocatchbothexceptions,对吧?...pass...Traceback(mostrecentcalllast):File"",line3,inFile''IndexError:listindexoutofbounds看起来像你'我重新尝试捕获这两个异常,但这不起作用。这个错误通常是由具有python2.x背景的开发人员犯的,因为在Python2中,此语法用于将异常绑定到可选参数。我们的代码应该已经捕获了IndexError异常。正确的方法是通过指定要在元组中捕获的所有异常并使用as绑定到参数来使用元组。Python2&3也支持这种语法:>>>try:...l=["a","b"]...int(l[2])...except(ValueError,IndexError)ase:...通过...>>>6。Python作用域规则的误解Python作用域解析是基于所谓的LEGB规则,它是Local、Enclosing、Global、Built-in的简写。但这会给开发人员带来问题,例如:>>>x=10>>>deffoo():...x+=1...printx...>>>foo()Traceback(mostrecentcallast):File"",line1,inFile"",line2,infooUnboundLocalError:localvariable'x'referedbeforeassignmentTraceback(mostrecentcalllast):file""in,line1文件"",line2,infooUnboundLocalError:赋值前引用的局部变量'x'没有意义我们已经声明x应该可以正常工作。调用函数会在这里寻找变量x,找不到变量x,就会把它带到外层作用域。在我们分配它之前它工作正常。我们得到UnboundLocalError以避免函数意外更改变量的值。浏览此处获取更多信息。为了进一步说明,这里有一些其他的例子:>>>lst=[1,2,3]>>>deffoo1():...lst.append(5)...>>>foo1()>>>lst[1,2,3,5]>>>lst=[1,2,3]>>>deffoo2():...lst+=[5]...>>>foo2()Traceback(mostrecentcallast):File"",line1,inFile"",line2,infooUnboundLocalError:localvariable'lst'referencedbeforeassignmentTraceback(mostrecentcall):file"online1in"file"",line2,infooUnboundLocalError:localvariable'lst'referencedbeforeassignment在这两种情况下,我们都尝试从外部范围更新列表。在第一个例子中它起作用了,但在第二个例子中它不起作用,因为我们在函数体中的那个列表上使用了赋值运算符。这将尝试将计算/评估的值存储到foo2中不存在的局部变量lst中。7.对Python如何在闭包中绑定变量感到困惑考虑以下示例:,>>>defcreate_multipliers():...return[lambdax:i*xforiinrange(5)]>>>formmultiplierincreate_multipliers():...printmultiplier(2)...您可能期望以下输出:02468但实际上得到:88888由于Python的后期绑定行为,它会在调用内部函数时搜索闭包中使用的变量值。所以在上面的代码中,无论何时调用任何返回的函数,都会在调用时在周围范围内搜索i的值,但是当发生这种情况时,循环已经完成,所以我已经给出了它i的最终值为4。解决方法是:>>>defcreate_multipliers():...return[lambdax,i=i:i*xforiinrange(5)]...>>>formmultiplierincreate_multipliers():...printmultiplier(2)..024688.重新发明轮子这在来自低级语言背景(例如c++、c#等)的开发人员中最为常见。由于庞大的社区和大量的开源内容以及对python社区的帮助,如果没有现有的解决方案,很难找到问题。但在这里,我说的是重新创建python提供的基础。其中一些可能包括使用装饰器、生成器、内置函数。我最好的例子是排序功能。当我为开发人员编写自定义排序函数以满足他们的独特需求时,我已经多次看到这种情况。在所有情况下,整个功能都可以用更简单、更优雅、更强大的代码代替:list.sort(key=...,reverse=...)很难找到不能解决我们问题的实用解决方案.我们甚至可以使用此方法对元组、字典或任何Python对象进行排序。请参见以下示例:>>>vowels=['e','a','u','o','i']>>>vowels.sort(reverse=True)>>>print('Sortedlist(inDescending):',vowels)Sortedlist(inDescending):['u','o','i','e','a']这是一个元组列表的例子#takesecondelementforsort#对第二个元素进行排序deftakeSecond(elem):returnelem[1]#randomlist#randomlistrandom=[(2,2),(3,4),(4,1),(1,3)]#sortlistwithkey#sortlistwithkeyrandom.sort(key=takeSecond)#printlist#printlistprint('Sortedlist:',random)输出:Sortedlist:[(4,1),(2,2),(1,3),(3,4)]总结:尽管Python很容易上手,但缺乏对所用工具或范例的深入了解可能会让您陷入困境。我希望你们中的一些人会发现