Python的缺点是什么?[关闭]


147

如今,Python似乎风行一时,而且并非不值得-因为它确实是一种语言,几乎有人喜欢用它来解决新问题。但是,正如一个智者曾经说过的(称他为智者,仅是因为我不知道是谁说的;不知道他是否真的是那个智者),真正懂一门语言的人不仅会知道它的语言,语法,设计等优点,但也有缺点。没有一种语言是完美的,有些只是比其他更好。

因此,您认为Python的客观缺点是什么。

注意:我不是在这里要求进行语言比较(即C#比Python更好,因为... yadda yadda yadda)-客观(某种程度上)认为哪些语言功能设计不当,是否,可能是什么?一些您在其中缺少的东西,依此类推。如果必须使用另一种语言作为比较,而仅仅是为了说明一个要点,否则很难对此进行详细说明(即,为了易于理解)


50
我认为这是一个有用的主观问题,将其关闭将很可惜。
埃里克·威尔逊

25
这里似乎有一个python-fanboy对所有反python答案都投了反对票。
zvrba 2010年

2
@TMN:仍然将空白视为标记,只是不返回它们-这正是Python语法所做的。

9
@Roger:关于SO的约定是评论下注。由于这是一个主观意见的网站,因此我认为没有理由投票。没有评论。因此,我坚持我的“呼唤”。
zvrba 2010年

8
@zvrba:投票一如既往仍然意味着“无用”。

Answers:


109

我经常使用Python,总的来说,我认为它是一种非常好的语言。但是,没有一种语言是完美的。以下这些缺点对我个人很重要:

  1. 太慢了 我的意思是真的,真的很慢。很多时候这并不重要,但这绝对意味着您需要另一种语言来处理那些对性能至关重要的位。

  2. 嵌套函数有点烂,因为您不能在外部范围内修改变量。 编辑: 由于支持库,我仍然使用Python 2,这个设计缺陷使我烦恼不已,但是由于非本地语句,显然它已在Python 3中修复。等不及要移植我使用的库,以便可以将该缺陷永久发送到历史的灰堆中。

  3. 它缺少一些可能对库/通用代码有用的功能,恕我直言,将其简单化为不健康的极端情况。我能想到的最重要的是用户定义的值类型(我猜它们可以用元类魔术创建,但我从未尝试过)和ref函数参数。

  4. 它离金属很远。需要编写线程原语或内核代码之类的东西吗?祝好运。

  5. 尽管我不介意缺乏预先捕获语义错误的能力来权衡Python提供的动态性,但我希望有一种方法可以捕获语法错误和愚蠢的事情,例如错误地混淆变量名,而不必实际运行代码。

  6. 该文档不如具有强大的公司支持的PHP和Java语言那样好。


60
@Casey,我不同意。索引太糟糕了-尝试在上查找with语句或方法list。教程中涉及的所有内容基本上都是不可搜索的。我对Microsoft的C ++文档更加满意。
Mark Ransom

17
大约5-只需使用pyflakes。它被编写为恰好捕获那些错误。
亚历山大·索洛维约夫

4
关于速度:随着PyPy的兴起,许多Python用户现在将能够通过使用带有内置JIT编译器的解释器来处理速度问题(目前,Python 3用户和cpyext未处理的C扩展模块用户)没有此选项)。
ncoghlan 2011年

29
我鄙视Python文档。当然,它们比大多数人还漂亮,但是很多时候很多有用的信息都集中在一页中,例如字符串和列表中的方法,而且所有序列类型也都集中在一起。当我搜索这些信息时,我只是落在一个巨大的书本上,而不得不向下搜索页面以查找所需内容。我也发现这些页面上的索引很难阅读,有时很难分辨我想要哪一部分。
卡森·迈尔斯,

5
与金属的距离如何成为争论?Python是否曾经声称自己是系统语言?
Mark Canlas 2012年

66

我讨厌Python无法区分变量的声明和用法。您无需进行静态输入即可实现这一目标。最好有一种方式说“这是我故意声明的变量,我打算引入一个新名称,这不是错字”。

此外,我通常以一次写入样式使用Python变量,也就是说,我将变量视为不可变的,并且在第一次分配变量后不对其进行修改。由于有了列表理解等功能,这实际上非常容易,并且使代码流更易于遵循。

但是,我无法证明这一事实。Python中没有什么阻止我覆盖或重用变量。

总之,我想用该语言有两个关键字:varlet。如果我写入未由任何一个声明的变量,Python应该引发错误。此外,将let变量声明为只读,而var变量为“普通”。

考虑以下示例:

x = 42    # Error: Variable `x` undeclared

var x = 1 # OK: Declares `x` and assigns a value.
x = 42    # OK: `x` is declared and mutable.

var x = 2 # Error: Redeclaration of existing variable `x`

let y     # Error: Declaration of read-only variable `y` without value
let y = 5 # OK: Declares `y` as read-only and assigns a value.

y = 23    # Error: Variable `y` is read-only

请注意,类型仍然是隐式的(但是let对于所有意图和目的,变量都是静态类型的,因为它们不能反弹到新值,而var变量仍可以动态类型)。

最后,所有方法参数应自动​​为let,即它们应为只读。除了以下习惯用法外,通常没有充分的理由来修改参数:

def foo(bar = None):
    if bar == None: bar = [1, 2, 3]

可以用稍微不同的惯用语代替:

def foo(bar = None):
    let mybar = bar or [1, 2, 3]

6
我非常希望Python有一个“ var”语句。除了您陈述的(非常好)原因之外,这也使阅读代码变得容易得多,因为您可以在页面上扫描以发现所有变量声明。
2011年

25
好像python开发人员忽略了过去的教训。不声明变量,不声明函数是1950年代首先犯的错误。那些难以发现的错字导致的难以发现的错误,在1950年代就已经足够令人惊讶了。一次又一次(多次纠正)此语言错误。声明变量不是很大的负担。它多次救了我的屁股。我不可避免地use strict;use warnings;在任何大小的脚本的Perl。Python剥夺了开发人员太多的调试辅助工具。
David Hammen

19
@David,公平起见,如果您尝试访问未分配的变量,它将引发异常。许多缺少声明的语言将返回某种默认值。结果,Python的版本比那些版本的问题要少得多。
温斯顿·埃韦特

1
@yi_H该提议并不旨在向后兼容,甚至不是真正的提议。问题是,“ Python的弊端是什么”……好吧,没有varlet(或类似机制)是一个弊端。换句话说:如果我是Python的设计师,我会做这样的事情。也就是说,当您加载特殊的程序包时(类似于),将来的版本可能包括此功能__future__。说,import strict。但是,这不会发生,因为它需要语法上的破解……
Konrad Rudolph

3
+1用于增加更好的“类似于功能”的编程能力。
伊万·普赖斯

44

我主要抱怨的是线程,由于全局解释器的锁定,线程在许多情况下(与Java,C和其他语言相比)表现不佳(请参阅“ Inside the Python GIL”(PDF链接))。

但是,有一个进程接口非常易于使用,但是对于相同数量的进程vs.线程,它将占用更多的内存,如果共享数据很多,则很难。但是,好处是,一旦您的程序可以处理多个进程,它就可以在多台计算机上扩展,而线程化程序则无法做到。

我对文档的批判确实不同意,我认为它是出色的,并且比大多数(如果不是全部)主要语言都更好。

另外,您还可以捕获运行pylint的许多运行时错误。


2
pyint +1。我没有意识到。下次我用Python做一个项目时,我会尝试一下。另外,如果您使用Jython而不是参考CPython实现,则多线程似乎可以正常工作。OTOH Jython的速度比CPython慢​​一些,因此这可能会部分破坏其目的。
dsimcha

3
线程支持不好吗?从2.1之前的版本开始就存在线程库。
rox0r

2
我知道有线程支持,但是与Java或C相比,GIL确实会降低性能。这就是为什么多处理模块优先于线程处理的原因。
cmcginty 2010年

2
如果您可以找到文档,则该文档很好。谷歌搜索Java类是比Python更容易。
布兰丹·朗

@Casey我已经在答案中阐明了措辞,因为支持线程,仅表现出一些奇怪的性能(也添加了参考资料和一些指向文档的链接)
dbr 2012年

28

可以说,缺少静态类型会导致某些类型的运行时错误,这不值得鸭子类型提供的增加的灵活性。


5
这是正确的,尽管有诸如PyChecker之类的工具可以检查诸如C / Java之类的编译器会执行的错误。
奥利弗·韦勒

24
动态类型化是一个有意识的设计决策,而不是缺点。
missingfaktor 2010年

14
就像说Java的弱点是缺乏动态类型一样。
MAK 2010年

12
@ missingfaktor,@ MAK,很明显,鸭式打字是预期的功能。但是大多数设计决策都会带来客观的利弊。增加的代码灵活性是动态键入的好处,而其他潜在的运行时错误类别则是一个缺点。主观部分是该功能是否值得。
Jacob

6
静态类型的缺乏使程序员更容易编写有运行时错误的代码。在C#中,int foo = 4; Console.Write(foo.Length);不会编译,因此错误“ Int32没有属性Length”不会意外地进入已发布的软件。在python中,除非您运行可选的辅助工具来查找类似的错误,否则访问对象的不存在成员的代码可能不会被检测到,直到最终导致运行时错误。
雅各布

27

我认为Python的面向对象的部分有点“被烙印”。您可以说,将“自我”显式传递给每个方法的全部需求是一个症状,即它的OOP组件没有明确计划。它还显示了Python有时谨慎的作用域规则,该规则在另一个答案中遭到批评。

编辑:

当我说Python的面向对象部分感到“笨拙”时,我的意思是有时OOP方面会感到相当不一致。以Ruby为例:在Ruby中,一切都是对象,您使用熟悉的obj.method语法调用方法(当然,重载的运算符除外);在Python中,一切也都是对象,但是有些方法是作为函数调用的;即,您重载__len__以返回长度,但是使用len(obj)而不是obj.length其他语言中更常见(更一致)的长度来调用它。我知道此设计决定背后有一些原因,但我不喜欢它们。

此外,Python的OOP模型缺乏任何类型的数据保护,即不会有私有,保护和公共成员; 你可以模仿他们使用_,并__在方法前面,但它是一种丑陋。


17
自参数仅让明确什么其他的语言留下隐。这些语言显然有一个“自我”参数。

13
@Roger Pate:是的,但是对“自我”的明确需求有点烦人(我认为这是一个泄漏的抽象)。它也不是有意的设计决定,而是由于Python的“怪异”作用域规则。我找不到快速的文章,但是Guido van Rossum发了一封电子邮件,很好地解释了为什么需要“ self”参数。
mipadi 2010年

2
@Roger Pate:在面向对象的语言中,将目标作为第一个参数传递仍可以视为实现细节。我的意思不是,不是一个好主意。关键是,在Python中,这不是由于有意识的设计决定,而是要解决范围系统中的疣。
mipadi 2010年

3
@mipadi:更新具有更好的推理(因此,我将删除downvote),但是如果您将len视为重载的运算符,则在Python中更多。希望看到有关Python如何使消息传递错误的示例或推理。

8
显式的自我是方法只是函数的事实的产物(正如Winston所指出的,隐式局部变量声明)。您可以随意不喜欢该设计决策,但是以一种在运行时可以将所有内容作为对象进行访问的语言来调用OOP 是“愚蠢的”。
ncoghlan 2011年

19

我不喜欢Python的事情:

  1. 线程化(我知道它已经被提及,但值得在每篇文章中提及)。
  2. 不支持多行匿名函数(lambda只能包含一个表达式)。
  3. 缺少一个简单但强大输入读取功能/类(像的cinscanf在C ++和C或ScannerJava中)。
  4. 默认情况下,所有字符串都不是unicode(但在Python 3中已修复)。

5
关于(2),我认为这被嵌套函数的可能性所抵消。
康拉德·鲁道夫

3
@KonradRudolph我的主要功能是嵌套函数而不是多行lambda,这是读取顺序被交换了。
CookieOfFortune 2012年

2
@wkschwartz:raw_input和'sys.stdin'都是准系统。他们不支持获取格式化的输入(例如,要及时读取的类似“%d:%d:%d”%(小时,分钟,秒))。到目前为止,Python还没有任何方法可以接近scanf(C语言)或Scanner(Java)功能。
MAK 2012年

2
@limscoder:默认情况下,所有字符串在Java中都是unicode。我认为没有单独的str和unicode类的充分理由。IMHO,字符串和字节数组应该通过相同的抽象表示。字符串类应该用于存储和处理文本-我们并不在乎其内部表示形式。我们不希望在字符串中的特定字节处执行诸如truncate / replace / delete / insert之类的操作-我们希望在特定字符处执行此操作。当输入非英语输入时,很容易忘记区别,并使您的代码崩溃。
MAK 2012年

1
@limscoder:如果您想查看简单的unicode,请尝试使用Tcl。几年前,我不得不从Tcl切换到Python,男孩惊讶于原始Python对unicode的支持有多大。它在Tcl中是真正不可见的,而在python中则是一个主要难题。
布莱恩·奥克利

18

具有可变数据类型的默认参数。

def foo(a, L = []):
    L.append(a)
    print L

>>> foo(1)
[1]
>>> foo(2)
[1, 2]

通常是一些细微错误的结果。我认为最好在需要默认参数的情况下创建一个新的列表对象(而不是创建用于每个函数调用的单个对象)。

编辑:这不是一个大问题,但是当需要在文档中引用某些内容时,通常意味着这是一个问题。这不是必需的。

def foo(a, L = None):
    if L is None:
        L = []
    ...

特别是当它应该是默认值时。这只是一种奇怪的行为,与您的预期不符,并且在很多情况下都没有用。


我对此有很多抱怨,但是为什么人们坚持要将一个空列表(该函数进行修改)作为默认参数?这真的是一个大问题吗?即,这是一个真正的问题吗?
马丁·维尔坎斯

8
它违反了最小惊讶原则。人们不会期望函数的参数在调用之间仍然存在。
aib 2012年

这是因为它是一种脚本语言。您只会一次被此错误困扰,以后再也不会。亲自找出该错误确实可以使您大吃一惊,以提醒您,是的,它仍然是一种脚本语言。但这仅仅是因为该语言在隐藏脚本方面(假设您正确使用了它)方面很有用。
Zoran Pavlovic

@ZoranPavlovic出于好奇,为什么这是脚本语言的结果?绑定数据的时间似乎很成问题,因为列表是可变的(这通常是两件好事,但当组合在一起时最终会变坏)。如果您在函数创建时绑定数据而不是在每次调用函数时都创建一个新列表,则在非脚本语言中可能会发生相同的问题。
jsternberg 2013年

@aib:我不这么认为-这里的参数和其他所有Python对象一样-是指向对象的指针。在这种情况下,对象是可变对象,并且在声明函数时绑定变量。该参数确实“在调用中生存”,但是幸存的是对可变对象的引用。
帕特里克·柯林斯

14

Python的某些功能使其灵活地成为一种开发语言,对于那些使用诸如C ++和Java之类的编译和链接过程进行的“整个程序”静态分析所使用的功能,也将其视为主要缺点。

  • 隐式声明局部变量

使用普通赋值语句声明局部变量。这意味着任何其他作用域中的变量绑定都需要编译器进行显式注释(外部作用域的全局和非本地声明,实例作用域的属性访问标记)。这极大地减少了编程时所需的样板数量,但是这意味着需要第三方静态分析工具(例如pyflakes)来执行由编译器以需要显式变量声明的语言处理的检查。

  • 支持“猴子修补”

模块,类对象甚至内置命名空间的内容都可以在运行时进行修改。这是非常强大的功能,允许使用许多非常有用的技术。但是,这种灵活性意味着Python不提供静态类型的OO语言所共有的某些功能。最值得注意的是,实例方法的“ self”参数是显式的,而不是隐式的(因为不必在类内部定义“方法”,因此可以在以后通过修改类来添加它们,这意味着它不是特别实用)隐式地传递实例引用),并且根据代码是在类的“内部”还是“外部”(因为该区别仅在执行类定义时存在),就不能轻易实施属性访问控制。

  • 远离金属

许多其他高级语言也是如此,但是Python倾向于抽象掉大多数硬件细节。像C和C ++这样的系统编程语言仍然更适合于处理直接的硬件访问(但是,Python将非常高兴地通过CPython扩展模块,或者更可移植地通过ctypes库与之对话)。


12
  1. 对代码块使用缩进,而不要使用{} / begin-end。
  2. 每种较新的现代语言都有适当的词法作用域,但Python没有(见下文)。
  3. 混乱的文档(与Perl5文档相比,非常好)。
  4. 海峡夹克(只有一种方法可以做到)。

范围界定破例;口译会议的笔录:

>>> x=0
>>> def f():
...     x+=3
...     print x
... 
>>> f()
Traceback (most recent call last):
  File "", line 1, in ?
  File "", line 2, in f
UnboundLocalError: local variable 'x' referenced before assignment

globalnonlocal引入了关键字来弥补这种设计上的愚蠢。


2
关于作用域,好奇地看一下python.org/dev/peps/pep-3104可能是值得的,以了解当前方法的原因。
Winston Ewert 2010年

同意+1。因此,+ 1。
Jas 2010年

34
拥有一种方法是一个优势。当您阅读别人的代码时,您将永远不会解密任何一条语句。一旦习惯用法扎根在您的大脑中,您就应该立即识别。
rox0r

9
完全同意@ rox0r。“直截了当”可防止各种语法大战。
keithjgrant 2011年

8
老实说,我很少需要Python中的globalor nonlocal关键字。很少有人忘记了这个问题的存在,尽管我每天都在工作中编写Python代码,但不得不反复搜索它几次。对我来说,需要修改全局变量(或更糟糕的是,外部非全局变量)的代码是代码的味道。通常(并非总是)有更好的方法。

11

我发现python的面向对象this.method()和过程/功能method(this)语法的组合非常令人不安:

x = [0, 1, 2, 3, 4]
x.count(1)
len(x)
any(x)
x.reverse()
reversed(x)
x.sort()
sorted(x)

这特别糟糕,因为大量函数(而不是方法)只是转储到全局名称空间中:与列表,字符串,数字,构造函数,元编程相关的方法,全部混合在一个大的按字母顺序排序的列表中。

至少,像F#这样的功能语言在模块中正确命名了所有函数:

List.map(x)
List.reversed(x)
List.any(x)

所以他们并不在一起。此外,这是整个库遵循的标准,因此至少是一致的。

我了解执行功能方法的事情的原因,但是我仍然认为将它们像这样混合起来是一个坏主意。如果遵循方法语法,至少对于常见操作,我会更加高兴:

x.count(1)
x.len()
x.any()
x.reverse()
x.reversed()
x.sort()
x.sorted()

无论方法是否在变异,将它们作为对象上的方法都具有以下优点:

  • 在单个位置查找数据类型上的“常见”操作:其他库/等。可能还有其他对数据类型可以做的事情,但是“默认”操作全部在对象的方法中。
  • Module调用时无需继续重复Module.method(x)。以上面的功能列表示例为例,为什么我必须List一遍又一遍地说?它应该知道它是一个List,我不想在上面调用该Navigation.map()函数!使用x.map()语法可使它保持DRY且仍然清晰。

当然,它比通用名称空间中的所有方法具有优势。并不是说当前的方法无法完成任务。它甚至很简洁(len(lst)),因为没有命名空间!我了解使用函数(默认行为等)优于方法的优势,但我仍然不喜欢它。

太乱了 在大型项目中,混乱是您最大的敌人。


1
是的...我真的很想念LINQ样式(我确定LINQ不是第一个实现它的人,但是我最熟悉它)列表处理。
CookieOfFortune 2012年

1
不要认为len(x)是一种方法。“ len”是一个函数。Python具有函数方法,我认为这种方法没有错。通常,缺少适当的功能是许多不必要的键入的来源。
rbanffy 2012年

我知道len()是一个函数,它有什么优点。我还说了为什么我认为这是一个坏主意,为什么我认为全局函数是一个特别不好的主意,以及为什么我认为方法提供了一种方便的方法来组织和确定功能范围=)
Haoyi 2012年

我认为42个关键字(或43个关键字)不是一个很大的数字。这也包括像defclass以及其他非函数调用。将其与其他大多数流行语言中的100+进行比较。另外,还要考虑从线import thisNamespaces are one honking great idea -- let's do more of those!。我认为您可能会误解Python名称空间;)
韦恩·沃纳

8

缺乏同质性

Python必须等待3.x添加“ with”关键字。在任何谐音语言中,它都可以轻松地添加到库中。

我在答案中看到的大多数其他问题是以下三种类型之一:

1)可以通过工具修复的事物(例如pyflakes)2)实施细节(GIL,性能)3)可以通过编码标准修复的事物(即人们不希望使用的功能)

#2并不是语言问题,IMO#1和#3并不是严重问题。


1
with可以从Python 2.5中使用from __future__ import with_statement,但是我同意,我偶尔发现不幸的是,像if/ for/ print/ etc 这样的语句是“特殊的”而不是常规函数
dbr 2012年

7

Python是我最喜欢的语言,因为它具有很高的表达力,但仍然可以避免您犯太多错误。我还有一些让我烦恼的事情:

  • 没有真正的匿名功能。Lambda可用于单语句功能,该with语句可用于在Ruby中使用代码块的许多事情。但是在某些情况下,它会使事情变得比实际情况更加笨拙。(远没有Java那样笨拙,但仍然...)

  • 模块和文件之间的关系有些混乱。从命令行运行“ python foo.py”与“ import foo”不同。Python 2.x中的相对导入也会引起问题。尽管如此,Python的模块仍然比C,C ++和Ruby的相应功能好得多。

  • 明确的self。即使我了解其中的某些原因,并且即使我每天都使用Python,但我还是会犯忘记它的错误。与此相关的另一个问题是,从模块中制作一个类变得有些乏味。显性的自我与他人抱怨的范围有限有关。Python中最小的作用域是函数作用域。如果您按照自己的意愿将函数缩小,那么这本身就不是问题,而且IMO通常会提供更简洁的代码。

  • len您希望某些全局函数(例如)是一种方法(它实际上是在幕后)。

  • 重大缩进。不是这个想法本身,我认为很棒,但是由于这是使许多人无法尝试Python的唯一原因,因此也许可以使用一些(可选)开始/结束符号来使Python更好。忽略那些人,我也完全可以适应缩进的尺寸。

  • 它不是Web浏览器的内置语言,而是JavaScript。

在这些投诉中,我只是非常关注我认为应该添加到语言中的第一个投诉。除了最后一个以外,其他的都比较小,如果发生的话会很棒!


+1这让我想知道是否应该写datetime.datetime.now()一个项目何时可以写datetime.now然后将两个项目混合在一起的一种写法排除了另一个项目,而且肯定不会在Java中发生,因为Java不会将模块命名为与文件相同(?)如果您看到在同时使用和明确使用这两种用法的情况下,模块似乎使我们与文件混淆的常见方式,self我仍然会尝试理解,因为调用的参数数量与函数的数量不同。您可能会认为VM python速度慢?
Niklas Rosencrantz

关于您的显式self关键字问题。我可能建议为此使用一个好的python IDE吗?我知道Eclipse上的PyDev如果检测到您正在编写类,则会自动完成函数签名的self部分。
Zoran Pavlovic

5

Python尚未完全成熟:此时的python 3.2语言与当前分发的大多数软件包都存在兼容性问题(通常它们与python 2.5兼容)。这是一个很大的缺点,当前需要更多的开发工作(查找所需的软件包;验证兼容性;权衡选择一个可能不太兼容的不太好的软件包;采用最佳版本,将其更新为3.2,这可能需要几天的时间;然后开始做一些有用的事情)。

可能在2012年中期,这将成为一个弊端。

请注意,我想我被一个狂热的男孩所鄙视。在开发人员讨论中,我们的高级开发人员团队得出了相同的结论。

从一个主要意义上讲,成熟度意味着团队可以使用该技术并非常快速地启动和运行,而没有隐患(包括兼容性问题)。如今,大多数第三方软件包的第3方python软件包和许多应用程序都无法在3.2下运行。这将导致更多的集成,测试,重新实现技术本身的工作,而不是解决眼前的问题==不太成熟的技术。

2013年6月更新:Python 3仍然存在成熟度问题。团队成员经常会提及所需的软件包,然后说“除了仅适用于2.6”(在某些情况下,我已经通过localhost套接字实现了变通方法,以将仅2.6的软件包与2.6一起使用,其余的我们的工具仅适用于3.2)。甚至纯Python Wiki MoinMoin都不是用Python 3编写的。


2
仅当您对成熟度的定义与设计上不兼容的版本不兼容时,我才与您同意。
tshepang 2011年

3
我同意python的两个不兼容的流是个问题(尽管可以理解为什么这样做了),但是我不认为这是“成熟度”的问题。
温斯顿·埃韦特

从某种意义上说,成熟度意味着团队可以使用该技术并非常快速地启动和运行,而没有隐藏的风险(包括兼容性问题)。如今,大多数第三方软件包的第3方python软件包和许多应用程序都无法在3.2下运行。这将导致更多的集成,测试,重新实现技术本身的工作,而不是解决眼前的问题==不太成熟的技术。
Jonathan Cline IEEE

2
然后只需使用Python2.x。您知道...每个人都在使用的版本。或阅读软件包文档2秒钟,以了解与哪个版本兼容。
jsternberg 2011年

2
“仅仅因为python 3.0已经发布了一段时间并不意味着它应该使用它的版本。Python3.0和2.x正在同时开发。我希望将来我们都能够使用python 3.0,但就目前而言,使用2.x是一个很好的解决方案”->这是一个500个字符的表达方式:尚未成熟。
Jonathan Cline IEEE

4

Python的作用域已严重破坏,这使得Python中的面向对象编程非常尴尬。


8
能给我举个例子吗?(我确定您是对的,但我想举个例子)
温斯顿·埃韦特

24
我喜欢Python,但绝对不愿意self.在每次引用实例属性和方法时都放在前面。就像使用Ruby一样容易,它使得无法使用Python创建DSL。
亚当·克罗斯兰

35
我没有发现自我尴尬,我喜欢露骨。
Winston Ewert 2010年

9
我不明白显性自我的重要意义。在C ++,Java和D中,人们经常通过约定使成员变量显式表示,例如,通过在它们前面加上下划线。
dsimcha

7
在与声明不同的方法中使用self:def foo(self)但self.foo()。我发现这种混合的显式定义和隐式的幕后内容不太好。
LennyProgrammers

4

我对Python的看法:

  • 固定的OOP(有关此问题的详细说明,请参见@mipadi的答案)
  • lambdas的执行失败
  • 范围问题
  • 标准库中没有持久性集合
  • 对嵌入式DSL的适应性差

为什么要下票?
missingfaktor

我不是拒绝投票的人,但是您能解释一下为什么您认为OO处于困境吗?Python一直都有面向对象,这是该语言的核心部分。
丹妮丝2011年

参见@mipadi的答案。
missingfaktor 2011年


4

Python中的访问修饰符不是强制性的-使其很难编写结构良好的模块化代码。

我想这是@Mason破坏范围的一部分-这种语言通常存在很大的问题。对于本来应该可读的代码,似乎很难确定在什么范围内可以和应该在什么范围内以及在任何给定时间点的值-由于这些缺点,我目前正在考虑从Python语言继续前进。

仅仅因为“我们都同意成年人”并不意味着我们不会犯错并且不能在一个强大的结构中更好地工作,尤其是在处理复杂的项目时-缩进和无意义的下划线似乎并不足够。


因此缺少访问控制是不好的……但是对任何非本地名称空间的变量写的显式作用域也是不好的?
ncoghlan 2011年

@ncoghlan:1-该功能是许多现代语言中的标准功能,具体取决于您配置项目的方式。2-在程序员的控制之下。3-不确定这样做有什么用-您可以使用大多数已编译语言/ IDE的一些项目设置轻松控制范围。如果“我们都是成年人”,我们应该能够做出自己的决定,并根据自己的舒适度调整范围。
矢量

2
事实是,要求“强制访问控制”的人们要求我们拿出使Python成为一种出色的胶合语言的原因之一:开发人员故意难以控制以后如何使用他们的代码。有多少C ++和Java模式的样板文件专门用于解决强制访问控制?我绝对可以理解,出于这些原因人们选择不使用Python,但是静态强制绝不能替代严格的测试。
ncoghlan 2011年

1
@ncoghlan-对我而言,关于Python的伟大之处在于语法的优雅性和简洁性-表现力。正如我所说的那样,范围界定与程序员弄乱他们不该做的事情无关,而与代码结构和组织无关。因此,“同意成年人”的概念尚无定论。我从事的是复杂的项目,而不是简单的实用程序和脚本-代码必须经过仔细的模块化和结构化-访问修饰符是确保这一点的最重要方法之一。
矢量

1
代码审查,培训和耦合分析等。对我来说,强制访问控制与静态类型属于同一类:它们确实有助于在正确性上提供一些额外的信心(但不足以避免需要进行广泛的测试),但是却提高了开发效率。(在实践上,类属性访问控件也不适合Python的对象模型,因为方法只是从类中检索的普通函数。类的“内部/外部”边界实际上并不存在,因此不能强制执行)
ncoghlan 2011年

3
  1. 效果不佳,但是随着pypy的提高,
  2. GIL阻止使用线程加速代码(尽管这通常是过早的优化),
  3. 它仅对应用程序编程有用,

但是它具有一些很棒的兑换功能:

  1. 非常适合RAD
  2. 与C的接口很容易(并且C可以嵌入python解释器),
  3. 可读性很强
  4. 很容易学习
  5. 有据可查
  6. 电池确实包含在内,它的标准库很大,而pypi包含了几乎所有模块,
  7. 它拥有一个健康的社区。

激发灵感的原因是什么?问题的问题。无论如何,您的意思是它仅对应用程序编程有用吗?还有什么其他程序?具体是什么不好?
tshepang 2010年

5
我列出了优点,因为我认为它们胜过缺点。您是否曾经尝试在python中实现Linux内核模块。
dan_waterworth 2010年

3

我确实喜欢python,我想到的第一个缺点是在注释一条语句时,例如,if myTest():您必须更改整个执行块的缩进,而不必使用C或Java。实际上,在python中,而不是注释掉if子句,我开始用这种方式注释掉它:`if True:#myTest()这样,我也不必更改以下代码块。由于Java和C不依赖缩进,因此使用C和Java可以更轻松地注释掉语句。


1
您是否会认真编辑C或Java代码以更改某些代码的块级别而不更改其缩进?

4
@Ben临时,是的……
另一种方式

1
@ben在这里一样。
Christopher Mahan,

2
我使用更改if something()为的技巧if False and something()。另一个技巧是使用多行字符串“注释掉”。
马丁·维尔坎斯

1
@马丁当然!如果错误...
Christopher Mahan

3

多重调度不能与已建立的单调度类型系统很好地集成,并且性能也不高。

在并行文件系统上,动态加载是一个巨大的问题,在此类文件系统中,类似POSIX的语义导致元数据密集型操作的灾难性减速。我的同事花了25万个核心小时的时间才将Python(带有numpy,mpi4py,petsc4py和其他扩展模块)加载到65k内核上。(该模拟提供了重要的新科学成果,因此值得这样做。但是,当燃烧一桶以上的油来装载Python时,这是一个问题。)无法静态链接迫使我们不得不做出巨大的扭曲来获取合理的大规模加载时间,包括修补libc-rtld以dlopen执行集体文件系统访问。


哇,技术性很强,您是否有与此主题相关的参考材料,示例,博客文章或文章?我想知道我是否会在不久的将来遇到这种情况。
森特2012年

阿伦在SciPy 2012上发表了演讲。这些dlopen东西在我们的collfs库中。该存储库还包含受Asher Langton的路径缓存启发的其他zipimport技巧。我们正在致力于更好的分发和论文。
杰德2012年

3
  • 相当广泛的一堆非常主流的第三方库和软件不是pythonic。一些示例:soaplib,openerp,reportlab。Critique不在范围之内,它在那儿被广泛使用,但是它使python文化混乱了(这打击了座右铭:“应该有一种-最好只有一种-显而易见的方式”)。已知的pythonic成功(例如django或trac)似乎是例外。
  • 实例,类,元类的潜在无限抽象深度在概念上是美丽而独特的。但是要掌握它,您必须深刻了解解释器(解释python代码的顺序等)。它并没有广为人知和使用(或正确使用),而类似的黑魔法(例如C#泛型)在概念上更令人费解(IMHO)似乎按比例更广为人知和使用。
  • 要掌握内存和线程模型,您必须对python有一定的经验,因为这里没有全面的规范。您只知道有效的方法,可能是因为您阅读了口译员的资料或经验丰富的怪癖,并发现了解决方法。例如,只有强引用或弱引用,而不是Java的软引用和幻象引用。Java有一个用于垃圾回收的线程,而对于何时在python中进行垃圾回收却没有正式的答案。您可以观察到,如果不执行任何python代码,则不会发生垃圾回收,并得出结论,在尝试分配内存时有时可能会发生垃圾回收。当您不知道为什么不释放锁定的资源时可能会很棘手(我的经验是freeswitch中的mod_python)。

无论如何,python是我四年来的主要语言。成为狂热分子,精英主义者或狂人并不是蟒蛇文化的一部分。


+1。内存和线程模型的规范就正确了。但是FWIW,线程上的Java垃圾收集器(以及有关GC的大多数其他内容)本身并不是Java语言或VM规范的一个方面,而是特定的JVM实现的问题。但是,主要的Sun / Oracle JVM在GC行为和可配置性方面得到了广泛的记录,以至于整本书都出版了有关JVM调整的书籍。理论上,不管语言规范如何,都可以用相同的方式记录CPython。
安德鲁·扬克

2
  • 奇怪的OOP:
    • len(s) 通过 __len__(self)和其他“特殊方法”
    • 可以从其他特殊方法(__add__以及__iadd__for ++=)派生而来的特殊方法
    • self 作为第一个方法参数
    • 您可以忘记调用基类构造函数
    • 没有访问修饰符(私有,受保护的...)
  • 没有常量定义
  • 自定义类型没有不变性
  • 吉尔
  • 糟糕的性能导致Python和C的混合使用以及构建问题(寻找C库,平台依赖项...)
  • 错误的文档,尤其是在第三方库中
  • Python 2.x和3.x之间不兼容
  • 不良的代码分析工具(与Java或C#等静态类型的语言提供的工具相比)

5
我个人认为2.x和3.x之间的不兼容性是Python的最大优势之一。当然,这也是一个缺点。但是,开发人员敢于打破向后兼容性的勇气也意味着他们不必无休止地进行繁琐工作。更多的语言需要这样的大修。
Konrad Rudolph 2012年

0

“不可变性”并不是它的强项。AFAIK数字,元组和字符串是不可变的,其他所有内容(即对象)都是可变的。将其与功能语言(如Erlang或Haskell)进行比较,后者一切都是不可变的(至少默认情况下是不可变的)。

但是,不可变性确实通过并发*闪耀,这也不是Python的强项,因此至少是必然的。

(* =对于nitpickers:我的意思是,并发至少部分是并行的。我猜想Python可以使用“单线程”并发,在这种情况下,不变性并不那么重要。(是的,喜欢FP的人,我知道不变性是即使没有并发也很棒。))


0

我很想拥有明确的并行结构。当我写一个列表理解像

[ f(x) for x in lots_of_sx ]

我不在乎元素的处理顺序。有时,我什至不在乎它们的返回顺序。

即使我的f是纯Python时CPython不能很好地做到这一点,也可以将此类行为定义为供其他实现使用。


//产生一堆线程//将队列que传递给所有线程que.extend([x对于lots_of_sx中的x]] que.wait()#等待所有的lots_of_sx被线程处理。
Zoran Pavlovic

0

Python没有尾调用优化,主要是出于哲学原因。这意味着在大型结构上进行尾递归可能会占用O(n)内存(由于保留了不必要的堆栈),并且需要您将递归重写为循环以获取O(1)内存。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.