with
是一个错误。尽管如此,我发现阅读这样的评论很有用:即使一个人不同意,也有很多可以学习的东西。是否有一篇博客文章或一些描述Python设计错误的书籍?例如,我猜测有些人会认为缺乏尾调用优化是一个错误;可能还有其他值得学习的问题(或非问题)。
with
是一个错误。尽管如此,我发现阅读这样的评论很有用:即使一个人不同意,也有很多可以学习的东西。bytes
与str
的更改。 - ismail print
作为一个函数是不方便的,而另一些人则认为这是一种改进。总的来说,变化并不是很多,大部分变化都非常小而微妙。例如, map()
和filter()
返回迭代器而不是列表,range()
的行为类似于以前的xrange()
,dict
方法如 dict.keys()
返回视图而不是列表。然后,还有一些与整数相关的更改,而最大的变化之一是二进制/字符串数据处理。现在它是文本和数据,而文本始终是Unicode。有几个句法更改,但它们更多的是关于一致性而不是重新设计整个语言。
从这个角度来看,自2.x版本以来,Python在语言(语法和语义)层面上已经被设计得非常好了。你可以对基于缩进的块语法进行争论,但我们都知道那样做没有任何意义... ;-)
另一种方法是看看其他Python实现尝试解决什么问题。它们中的大多数以某种方式解决性能问题,有些解决平台问题,有些通过对语言本身进行添加或更改来更有效地解决某些任务。Unladen swallow 通过优化运行时字节编译和执行阶段来显著加快Python的速度。Stackless 添加了用于高效、大量线程应用程序的功能,如微线程和任务、通道以允许双向任务通信、调度以协同或抢占地运行任务以及序列化以暂停和恢复任务执行。Jython 允许在Java平台上使用Python,而IronPython 则在.Net平台上使用。Cython 是一种允许调用C函数和声明C类型的Python方言,使编译器能够从Cython代码生成高效的C代码。Shed Skin 将隐式静态类型引入Python,并为独立程序或扩展模块生成C++。PyPy 在Python的子集中实现了Python,并更改了一些实现细节,例如添加垃圾回收而不是引用计数。其目的是通过更高级别的语言使Python语言和实现开发变得更加高效。Py V8 通过V8 JavaScript引擎桥接Python和JavaScript,可以说它正在解决平台问题。Psyco 是一种特殊的JIT,动态生成正在处理的数据的运行代码的特殊版本,这可以为您的Python代码提供加速,而无需编写优化的C模块。从PEP-3146可以了解到Python的现状,该文档概述了Unladen Swallow如何被合并到CPython中。这个PEP已经被接受,因此Python开发人员认为这是目前最可行的方向。请注意,它解决的是性能问题,而不是语言本身。
所以我认为Python主要的设计 问题 在于性能领域 - 但这些基本上是任何动态语言都必须面对的挑战,Python语言和实现家族正在努力解决这些问题。至于像Javascript: the good parts中列出的明显设计 错误,我认为“错误”的含义需要更明确地定义,但您可能想查看以下内容以获取思考和意见:
我对Python最大的不满是标准库中缺乏适当的命名规范,而这在迁移到3.x版本时并没有得到真正的解决。
例如,为什么datetime
模块本身包含一个名为datetime
的类?(更不用说为什么我们有单独的datetime
和time
模块,但也有一个datetime.time
类!)为什么datetime.datetime
是小写字母,但decimal.Decimal
是大写字母呢?另外,请告诉我,在xml
命名空间下为什么存在那么混乱的情况:xml.sax
,而xml.etree.ElementTree
却不同-这是怎么回事?
isinstance
、startswith
、issubset
、deleteacl
、endheaders
... - mernen请尝试以下链接:
这些链接可能对IT技术有所帮助。许多经验不足的开发者常常犯一些候选错误,其中之一就是默认参数:
http://www.deadlybloodyserious.com/2008/05/default-argument-blunders/
我个人在语言方面有一个小问题,就是关于lambdas / local functions的名称绑定:
fns = []
for i in range(10):
fns.append(lambda: i)
for fn in fns:
print(fn()) # !!! always 9 - not what I'd naively expect
在我的看法中,声明时查找lambda引用的名称更好。我理解它现在的工作方式的原因,但还是觉得不太方便...
你目前需要通过在函数闭包中将i
绑定到一个值不会改变的新名称来解决这个问题。
lambda i=i: i
的技巧。 - Peakerif
块等)和函数调用提供一个新的词法作用域,而没有闭包的语言(例如 C)通常会这样做。不幸的是,在 JS 中使用的解决方法,例如像 Array::forEach
这样使每次迭代成为函数调用并因此给它们自己的词法作用域,对于 Python 来说不是一个选项,因为它的 lambda 函数太弱了。 - 00dani这是语言的一个小问题,而不是基本错误,但是:属性覆盖。如果您覆盖属性(使用getter和setter),没有简单的方法可以获取父类的属性。
是的,这很奇怪,但我想这就是使用可变变量的后果。
我认为原因在于“i”指的是一个具有可变值的盒子,而“for”循环会随着时间的推移改变该值,因此稍后读取盒子值将得到唯一剩下的值。 除非将其变成没有可变变量的函数式编程语言(至少没有未经检查的可变变量),否则我不知道如何解决这个问题。
我使用的解决方法是创建一个带有默认值的新变量(Python中的默认值在定义时计算,这在其他时候很麻烦),这会导致将值复制到新盒子中:
fns = []
for i in range(10):
fns.append(lambda j=i: j)
for fn in fns:
print(fn()) # works
1 is (4-3)
进行验证。因此,该对象不会发生变异,但名称“i”已更新为引用新对象。这就是我所指的错误。将j=i
分配会导致名称“j”引用在那个时间点 i
所引用的对象。j
是存储在新lambda对象上的名称,并且不会被重新定义为引用其他任何内容,因此对整数对象的命名引用保持不变。 - Tom Whittock我觉得很惊讶,没有人提到全局解释器锁。