当前位置: 首页 > 科技观察

Python也许很友好,但它也容易弄得一团槽_1

时间:2023-03-17 16:36:58 科技观察

Python可能很友好,但也容易乱七八糟,是编程初学者最好的语言之一。他们没有错,但这并不意味着Python不会让编程新手感到困惑。  以动态类型为例,似乎令人惊讶的是,Python可以自己弄清楚一个变量可能会得到什么类型的值,而且它不需要浪费一行代码来声明类型,这样速度更快。  一开始是这样的,然后你搞砸了一行,整个项目甚至在运行之前就崩溃了。  公平地说,许多其他语言都使用动态类型,但对于Python来说,这只是坏名单的开始。隐式声明变量会使代码变得一团糟  几年前,当我开始攻读博士学位时,有一篇关于它的文档。  但我仍然需要阅读数千行Python代码,以确保我知道每段代码的作用,以便我可以将我想到的新功能放在那里,这就是问题所在......  有代码中到处都是未声明的变量,为了了解每个变量的作用,我必须在整个文件中搜索它,更常见的是整个项目。  还有一个复杂的情况就是变量通常在一个函数内部被调用,但是当这个函数被调用的时候其他的东西被调用了...还有一种情况是一个变量可以与一个类交织在一起,这个类与另一个类的另一个变量反过来影响一个完全不同的类......你明白了。  我不是唯一有这种经历的人。《Python之禅》明明说显式比隐式好,但是在Python中做隐式变量太容易了,尤其是在大型项目中,很快就会出问题。可变类型无处不在——即使在函数b=0中):  returna+b+5  work:add_five(3)#Return8add_five(3,4)#Return12  因为表达式b=0将b定义为整数,而整数是不可变的:defadd_element(list=[]):  list.append("foo")  returnlistadd_element()#按预期返回["foo"]  到目前为止一切顺利,但是如果我再次执行它会发生什么?add_element()#返回["foo","foo"]!卧槽!由于参数是一个列表,即list["foo"]已经存在,Python只是将其内容附加到该列表,这样做是因为列表与整数不同,列表是可变类型。俗话说:“疯狂就是一遍又一遍地做同样的事情并期待不同的结果”(这句话经常被误认为是爱因斯坦)。也可以说,带有可选参数和可变对象的Python很疯狂。类变量也不安全  如果你认为这些问题仅限于可变对象作为可选参数的情况,那你就错了。  如果您进行面向对象编程(几乎每个人都这样做),那么类在Python代码中无处不在,并且类最有用的特性之一是继承。  这只是一种奇特的说法,如果你有一个具有某些属性的父类,你可以创建一个继承它的属性的子类,像这样:classparent(object):  x=1classfirstchild(parent):  passclasssecondchild(parent):  passprint(parent.x,firstchild.x,secondchild.x)#returns111  这不是一个特别好的例子,所以不要复制在您的代码项目中。关键是,子类继承了x=1,所以我们调用它,得到的结果和父类一样。  此外,如果我们更改子类的x属性,它应该只更改该子类。就像你在十几岁时染了头发一样,它不会改变你父母或兄弟姐妹的头发,所以这很好。firstchild.x=2print(parent.x,firstchild.x,secondchild.x)#返回121  你小时候妈妈给你染头发是怎么回事?你的头发没有变,对吧?parent.x=3print(parent.x,firstchild.x,secondchild.x)#return323这是因为Python的方法解析顺序,只要没有特别说明,子类继承父类的一切,所以,在Python的世界里,如果你不提前抗议,妈妈给你染头发的时候就给你染。范围有时会反转  这个下一级让我绊倒了很多次。  在Python中,如果在函数内部定义了一个变量,那么这个变量将不会在函数外部起作用,有人说它超出了范围:defmyfunction(number):  basenumber=2  returnbasenumber*numberbasenumber##哦不!这是错误:#Traceback(mostrecentcalllast):#File"",line1,in#NameError:name'basenumber'isnotdefined  这应该是相当直观的(不,我没有偶然发现这点)。  反过来呢?我的意思是,如果我在函数外部定义一个变量并在函数内部引用它会发生什么?x=2defadd_5():  x=x+5  print(x)add_5()##哦亲爱的...#Traceback(最近调用最后):#File"",line1,in#File"",line2,inadd_y#UnboundLocalError:localvariable'x'referencedbeforeassignment奇怪,对吧?如果阿尔伯特生活在一个有树的世界里,而阿尔伯特住在一所房子里,那么阿尔伯特一定知道树长什么样子?(树是x,Albert的房子是add_5(),Albert是5...)  这个问题我遇到过很多次了,在一个类中,定义一个被另一个类调用的函数时,我花了找了半天问题的根源。  这背后的想法是函数内部的x与外部的x不同,因此您不能只更改它。就像如果阿尔伯特只是在梦想把树变成橙色,那当然不会让树真正变成橙色。  幸运的是,这个问题有一个简单的解决方案,只需在x前添加一个global即可!x=2defadd_5():  globalx  x=x+5print(x)add_5()#有效!所以如果你认为作用域只是保护函数内部的变量不受外界影响,那么请再想一想。在Python中,外部世界受到局部变量的保护,就像阿尔伯特不能用他的思想力量把树涂成橙色一样。在迭代列表时修改列表  我自己也遇到过几次这种废话。  想想这个:mynumbers=[xforxinrange(10)]#thisis[0,1,2,3,4,5,6,7,8,9]forxinrange(len(mynumbers)):  ifmynumbers[x]%3==0:  mynumbers.remove(mynumbers[x])##Ew!#Traceback(最近调用last):#File"",第2行,in#IndexError:listindexoutofrange  这个循环不起作用,因为它每隔一段时间就从列表中删除一个元素。因此,列表的末尾向前移动,则不可能到达元素编号10,因为它已经不存在了!  一个简单方便的解决方案,给所有要移除的元素赋一个不切实际的值,在下一步中删除它们。  但有一个更好的解决方案:mynumbers=[xforxinrange(10)ifx%3!=0]#这就是我们想要的![1,2,4,5,7,8]  一行代码!  请注意,我们在上面的示例中使用了Python列表理解来调用列表。它是方括号[]中的表达式,循环的简写,列表理解通常比常规循环快一点,如果您处理大型数据集,这很酷。  在这里,我们只是添加了一个if子句来告诉列表理解它不应该包含被3整除的数字。与上面描述的一些现象不同,列表理解不是Python的糟糕设计,而是Python的天才设计,尽管初学者一开始可能会遇到这个问题。地平线上的一些曙光在过去,当涉及到与Python相关的问题时,编码并不是唯一的难题。Python过去也非常慢,比大多数语言慢2到10倍。现在好多了,例如,Numpy包在处理列表、矩阵等方面非常快。  使用Python也可以更轻松地进行多处理。这使您可以使用计算机的所有2个、16个或更多个内核,而不仅仅是一个。我已经在20个内核上运行它,它为我节省了数周的计算时间。此外,随着机器学习在过去几年取得的进步,Python表明它还有很长的路要走。像Pytorch和Tensorflow这样的包让机器学习变得非常容易,其他语言都在努力跟上。  Python这些年来越来越好,但是,这个事实并不能保证光明的未来,Python仍然不笨,请谨慎使用。译者介绍  王德真,51CTO社区编辑,10年互联网产研经验,6年IT教育培训行业经验。前K12教育上市公司产品经理,技术博客专家,蓝桥签约作者,《滚雪球学Python》栏目作者,《爬虫100例》栏目特约作者,78技术人社区发起人。  原标题:Python可能很简单,但一团糟  链接:https://thenextweb.com/news/python-may-be-easy-but-its-a-mess