it-swarm.cn

Python的缺点是什么?

如今,Python似乎风靡一时,而且并非不值得-因为它确实是一种语言,几乎有人喜欢用它来解决新问题。但是,就像一个聪明的人曾经说过(称他为聪明的人一样,只是因为我不知道是谁说的;不知道他在那个时候是否那么聪明全部),要真正了解一种语言,不仅要知道其语法,设计等优点,还要知道其缺点。没有一种语言是完美的,有些只是比其他的要好。

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

注意:我在这里不要求进行语言比较(即C#比Python,因为... yadda yadda yadda)更好)-更多是一个目标(某种程度上)判断哪些语言功能设计不当,是否,您可能缺少哪些功能,等等。如果必须使用另一种语言作为比较,但仅仅是为了说明一个很难解释的观点(例如,易于理解)

147
Rook

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

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

  2. 嵌套函数有点烂,因为您不能在外部范围内修改变量。 编辑:由于库的支持,我仍然使用Python= 2,这种设计缺陷激怒了我,但是由于 nonlocal 语句,显然它已在Python 3)中修复。历史堆永远。

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

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

  5. 虽然我不介意缺乏预先捕获语义错误的能力,但这是对Python提供,我希望有一种方法可以捕获语法错误和愚蠢的事情,例如错误地命名变量名,而不必实际运行代码。

  6. 该文档不如PHP和Java)具有强大的公司支持。

109
dsimcha

我讨厌Python不能区分变量的声明和用法。您不需要静态类型就可以做到这一点。)有一种说“ this是我故意声明的变量,我intend引入了一个新名称,这不是错字。”.

此外,我通常以一次写入的方式使用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]
66
Konrad Rudolph

我的主要抱怨是线程,由于全局解释器锁定(在 “ Python GIL内部)”中,在许多情况下(与Java,C和其他环境相比),线程的性能不佳。 (PDF链接) 谈话)

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

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

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

44
cmcginty

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

28
Jacob

我认为Python的面向对象的部分感觉像是“固定”。您可能会说,显式地将“自我”传递给每个方法的全部征兆是它的OOP组件没有明确计划planned。它还显示了Python有时谨慎的作用域规则,该规则在另一个答案中遭到批评。

编辑:

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

另外,Python的OOP模型缺乏任何形式的数据保护,即没有私有,受保护的成员和公共成员。您可以在方法前面使用___和____模仿它们,但这有点丑陋。同样,Python也不会正确正确获得OOP的消息传递方面。

27
mipadi

我不喜欢Python的事情:

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

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

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 = []
    ...

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

18
jsternberg

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

  • 隐式声明局部变量

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

  • 支持“猴子修补”

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

  • 远离金属

许多其他高级语言也是如此,但是Python往往会抽象出大多数硬件细节。像C和C++这样的系统编程语言仍然更适合处理直接的硬件访问(但是, Python会很高兴地通过CPython扩展模块,或者更方便地通过ctypes库与那些人交谈)。

14
ncoghlan
  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关键字来修补此设计愚蠢问题。

12
zvrba

我发现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)
_

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

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

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

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

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

当然,它比放入全局命名空间中的一切方式更有优势。这并不是说目前的方式无法完成工作。它甚至很简洁(len(lst)),因为没有命名空间!我了解使用函数(默认行为等)相对于方法的优势,但我仍然不喜欢它。

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

11
Haoyi

缺乏 同音性

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

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

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

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

8
Jason

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

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

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

  • 显式self。即使我了解其中的某些原因,并且即使每天使用Python),我也常常会犯下忘记它的错误。它的另一个问题是,它变得有些繁琐从模块中创建类。显式self与其他人抱怨的有限范围有关。Python的最小范围是函数范围。应该,这本身不是问题,而IMO通常会提供更简洁的代码。

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

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

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

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

7
Martin Vilcans

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

很有可能在2012年中期,这将是一个弊端。

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

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

2013年6月更新:Python 3仍然存在成熟度问题。每隔一个团队,成员会经常提及所需的软件包,然后说“除了仅适用于2.6”(在某些情况下,我会ve通过localhost套接字实现了一种变通方法,以在2.6中使用仅2.6包,而我们的其他工具仍在3.2中使用。)甚至连纯Python Wiki MoinMoin也不用Python = 3。

5
Jonathan Cline IEEE

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

4
Mason Wheeler

Python中的访问修饰符不可强制执行-很难编写结构良好的模块化代码。

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

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

4
Vector

我对Python的看法:

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

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

动态加载是并行文件系统上的一个大问题,在并行文件系统上,类似POSIX的语义导致元数据密集型操作的灾难性速度下降。我的同事已经花了25万个核心小时,而仅仅Python(带有numpy,mpi4py,petsc4py和其他扩展模块))已加载到65,000个内核上。结果,所以这是值得的,但是当燃烧一桶以上的油以装载Python一次)。这是一个问题。无法进行静态链接迫使我们不得不大加扭曲。获得合理的合理加载时间,包括修补libc-rtld以使dlopen执行集体文件系统访问。

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

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

3
vincent

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

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

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

  1. 非常适合RAD
  2. 与C交互很容易(并且C可以嵌入python解释器)),
  3. 可读性很强
  4. 很容易学习
  5. 有据可查
  6. 电池确实包含在内,它的标准库很大,而pypi包含了几乎所有模块,
  7. 它拥有一个健康的社区。
3
dan_waterworth
  • 奇怪的OOP:
    • len(s)__len__(self)和其他“特殊方法”
    • 可以从其他特殊方法(__add____iadd__++=
    • self作为第一个方法参数
    • 您可以忘记调用基类构造函数
    • 没有访问修饰符(私有,受保护的...)
  • 没有常量定义
  • 自定义类型没有不变性
  • 吉尔
  • 糟糕的性能导致Python和C的混合使用,以及构建问题(寻找C库,平台依赖性...)
  • 错误的文档,尤其是在第三方库中
  • Python 2.x和3.x之间不兼容
  • 不良的代码分析工具(与为静态类型的语言(例如Java或C#)提供的语言相比)
2
deamon

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

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

(* =对于nitpickers:我的意思是并发至少部分是并行的。我猜Python对于“单线程”并发是可以的,其中不变性并不那么重要。(是的, FP爱好者,我知道即使没有并发性,不变性也很好。

0
Kosta

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

[ f(x) for x in lots_of_sx ]

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

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

0
rbanffy

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

0
a3nm