最近ではPythonが大流行しているように思われますが、それは当然のことですが、Pythonは本当に解決すべき新しい問題を与えられている言語であるからです。しかし、賢い人として一度言った(彼を賢い人と呼ぶ)誰が実際にそれを言ったのか私にはわからないだけです;彼がそんなに賢明であったかどうかはわかりません)、言語を本当に知ることは、その構文、デザインなどだけでなく、利点も知っています。完璧な言語はありません。他の言語よりも優れている言語もあります。
では、あなたの意見では、Pythonの客観的な欠点は何でしょうか。
注:ここでは言語比較を求めていません(つまり、C#はPythonより良いので... yadda yadda yadda)-より多くの目的(ある程度)、どの言語機能がうまく設計されていないのか、おそらく、何が不足しているのか、などの意見です。別の言語を比較として使用する必要があるが、詳しく説明するのが難しい点を説明するだけの場合それ以外の場合(つまり、理解を容易にするため)
私はPythonを定期的に使用していますが、全体としては非常に優れた言語だと思います。それでも、完璧な言語はありません。個人的に重要な順に、次の欠点があります。
遅いです。本当に遅いです多くの場合、これは重要ではありませんが、パフォーマンスが重要なビットには別の言語が必要になることは間違いありません。
入れ子関数は、外側のスコープの変数を変更できないという点で問題があります。 編集:ライブラリのサポートのため、Python 2をまだ使用しています。この設計上の欠陥により、私をいらいらさせます。 nonlocal ステートメントにより、Python 3で修正されているようです。使用するライブラリが移植されるのを待つことができないため、この欠陥を灰に送信できます永遠の歴史の山。
ライブラリ/ジェネリックコードに役立つ可能性のあるいくつかの機能が欠けています。IMHOは、不健康な極端に取られたシンプルさです。私が考えることができる最も重要なものは、ユーザー定義の値型(これらはメタクラスマジックで作成できると思いますが、私は試したことはありません)、およびref関数パラメーターです。
それは金属から遠いです。スレッド化プリミティブやカーネルコードなどを記述する必要がありますか?幸運を。
セマンティックエラーをキャッチする能力の欠如は、Python申し出、私は実際にコードを実行しなくても、構文エラーや変数名のタイプミスのような愚かなことをキャッチする方法があったらいいのにと思います。
ドキュメントはPHPやJavaのような企業の強力な裏付けがあるような言語ほどは良くありません。
Pythonは変数の宣言と使用法を区別できないので嫌いです。それを実現するために静的型付けを行う必要はありません。これを言う方法があればいいのです。は、私が故意に宣言する変数であり、私は新しい名前を導入するためにintendです。これはタイプミスではありません。」.
さらに、私は通常、Python変数を1回限りのスタイルで使用します。つまり、変数を不変として扱い、最初の割り当て後にそれらを変更しません。リストの理解などの機能のおかげで、これは実際には信じられないほど簡単で、コードフローの追跡がより簡単になります。
ただし、その事実を文書化することはできません。 Pythonには何もないので、変数を上書きしたり再利用したりすることができません。
まとめると、var
とlet
という2つのキーワードをこの言語で使用したいと思います。どちらでも宣言されていない変数に書き込むと、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]
私の主な不満はスレッド化です。これは、グローバルなインタープリターロックのため、多くの状況で(Java、Cなどと比較して)パフォーマンスが劣ります( "Inside Python GIL"を参照してください。 (PDFリンク) トーク)
ただし、非常に使いやすい マルチプロセスインターフェイス がありますが、同じ数のプロセスとスレッドのメモリ使用量が重くなるか、共有データが多い場合は難しくなります。 。ただし、利点は、一度複数のプロセスでプログラムを処理すると、スレッド化されたプログラムでは実行できない、複数のマシンにまたがってスケーリングできることです。
私はドキュメンテーションの批評に本当に同意しません、それは優秀であり、そこにあるすべての主要な言語ではないにしてもほとんどの言語より優れていると思います。
また、実行中の pylint のランタイムバグの多くを捕捉できます。
間違いなく、runtimeエラーの特定のクラスを導入する可能性がある静的型付けの欠如は、ダック型付けが提供する追加の柔軟性に値しません。
Pythonのようなオブジェクト指向の部分は「ボルトオン」のような感じです。すべてのメソッドに明示的に「自己」を渡す必要があるということは、それがOOPコンポーネントは明確に計画されていなかった計画されたと言うこともできます;これはまた、別の回答で批判されたPythonの時々いびつなスコープルールを示しています。
編集:
Pythonのオブジェクト指向の部分が「ボルトオン」されていると感じるとき、私はOOPサイドがかなり一貫していないように感じることを意味します。Rubyを例にとると、In Ruby、everythingはオブジェクトであり、おなじみのobj.method
構文を使用してメソッドを呼び出します(もちろん、オーバーロードされた演算子を除く)。Pythonでは、すべてもオブジェクトです。ただし、一部のメソッドは関数として呼び出します。つまり、長さを返すために__len__
をオーバーロードしますが、他の言語で一般的な(そして一貫した)obj.length
共通の代わりにlen(obj)
を使用して呼び出します。理由はわかっています。この設計決定の背後にありますが、私はそれらが好きではありません。
さらに、PythonのOOPモデルにはデータ保護の種類がありません。つまり、プライベートメンバー、保護されたメンバー、パブリックメンバーがないため、メソッドの前で_
と__
を使用してそれらを模倣できますが、同様に、Pythonはquiteを取得しませんOOPどちらかです。
Pythonについて私が気に入らない点:
lambda
に含めることができる式は1つだけです)。cin
またはscanf
、JavaではCまたはScanner
など)。可変データ型のデフォルト引数。
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 = []
...
特にそれがデフォルトであるべきだったとき。これは、予想とは異なる奇妙な動作であり、多くの状況では役に立ちません。
開発言語のように柔軟性を高めるPythonの機能のいくつかは、C++やJavaなどの言語でのコンパイルおよびリンクプロセスによって実行される「プログラム全体」の静的分析に使用される機能によっても、主要な欠点と見なされます。
ローカル変数は、通常の代入ステートメントを使用して宣言されます。これは、他のスコープの変数バインディングでは、コンパイラーが明示的なアノテーションを取得する必要があることを意味します(外部スコープのグローバルおよび非ローカル宣言、インスタンススコープの属性アクセス表記)。これにより、プログラミング時に必要なボイラープレートの量が大幅に削減されますが、明示的な変数宣言を必要とする言語でコンパイラーによって処理されるチェックを実行するには、サードパーティの静的分析ツール(pyflakesなど)が必要です。
モジュール、クラスオブジェクト、さらには組み込みの名前空間の内容も、実行時に変更できます。これは非常に強力であり、多くの非常に有用なテクニックを可能にします。ただし、この柔軟性は、Pythonが静的に型指定されたOO言語に共通するいくつかの機能を提供しないことを意味します。最も重要なのは、インスタンスメソッドへの "self"パラメータが明示的であることです。暗黙的ではなく(「メソッド」はクラス内で定義する必要がないため、後でクラスを変更することによって追加できます。つまり、インスタンス参照を暗黙的に渡すことは特に実用的ではありません)、属性アクセスコントロールはコードがクラスの「内部」または「外部」であるかどうかに基づいて容易に適用されます(その区別はクラス定義の実行中にのみ存在するため)。
これは他の多くの高水準言語にも当てはまりますが、Pythonはほとんどのハードウェアの詳細を抽象化する傾向があります。CやC++などのシステムプログラミング言語は、直接ハードウェアアクセスの処理にはるかに適しています(ただし、 Pythonは、CPython拡張モジュールを介して、またはより移植性の高いctypes
ライブラリを介して、それらと非常に楽しく話をします)。
スコープの破損の例。通訳セッションからの筆記録:
>>> 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
global
およびnonlocal
キーワードがこの設計の愚かさを修正するために導入されました。
オブジェクト指向this.method()
と手続き型/関数型method(this)
構文のpythonの組み合わせは非常に不安定です:
_x = [0, 1, 2, 3, 4]
x.count(1)
len(x)
any(x)
x.reverse()
reversed(x)
x.sort()
sorted(x)
_
(メソッドではなく)多数の関数が global namespace にダンプされるだけなので、これは特に悪いです:リスト、文字列、数値、コンストラクター、メタプログラミングに関連するすべてのメソッドが1つの大きなアルファベット順にソートされたリスト。
少なくとも、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が保持され、あいまいさがなくなります。そしてもちろん、それはそれを行うput-everything-in-global-namespaceの方法よりも優れています。現在の方法では、物事を成し遂げることができないわけではありません。名前空間が何もないので、かなり簡潔です(len(lst)
)。メソッドよりも関数(デフォルトの動作など)を使用する利点を理解していますが、それでも好きではありません。
汚いだけです。そして、大きなプロジェクトでは、混乱はあなたの最悪の敵です。
ホモニコ性 の欠如。
Pythonは3.xが「with」キーワードを追加するのを待たなければなりませんでした。同型の言語であれば、ライブラリに追加することもできます。
回答で見た他のほとんどの問題は、3つのタイプのいずれかです。
1)ツールで修正できるもの(例:pyflakes)2)実装の詳細(GIL、パフォーマンス)3)コーディング標準で修正できるもの(つまり、ユーザーが望んでいない機能)
#2は言語の問題ではなく、IMO#1と#3は深刻な問題ではありません。
Pythonは非常に表現力豊かなので、私のお気に入りの言語ですが、それでも多くの間違いを犯すことはありません。私はまだ私を困らせるいくつかのことを持っています:
本当の匿名関数はありません。 Lambdaは単一ステートメント関数に使用でき、with
ステートメントはRubyでコードブロックを使用する多くの場合に使用できます。しかし、状況によっては、必要以上に不格好なものになります。 (Javaの場合と同じように不器用ですが、それでも...)
モジュールとファイルの関係に混乱があります。コマンドラインから「python foo.py」を実行することは、「import foo」とは異なります。 Python 2.xでの相対インポートも問題を引き起こす可能性があります。それでも、Pythonのモジュールは、C、C++、Rubyの対応する機能よりもはるかに優れています。
明示的self
。その理由のいくつかは理解していますが、Pythonを毎日使用していますが、忘れてしまう傾向があります。もう1つの問題は、モジュールからクラスを作成します。明示的な自己は、他の人が不満を述べている限定的なスコープに関連しています。Pythonの最小スコープは関数スコープです。関数を小さくしておくと、それ自体は問題ではなく、IMOはよりクリーンなコードを提供します。
len
など、メソッドであることが期待されるいくつかのグローバル関数(実際には裏で実行されています)。
重要なインデント。私は素晴らしいと思うアイデア自体ではありませんが、これは非常に多くの人々がPythonを試さないようにする唯一の方法であるため、おそらくPythonこれらの人々を無視して、私はインデントのために強制されたサイズで完全に生きることができました。
JavaScriptではなく、Webブラウザーの組み込み言語ではありません。
これらの苦情のうち、私が十分に気にかけているのは、言語に追加する必要があると思う最初の苦情だけです。最後の1つを除いて、他のものはかなりマイナーです。
Pythonは完全に成熟していません。python 3.2言語は、現在配布されているほとんどのパッケージと互換性の問題があります(通常、python 2.5)。これは、現在より多くの開発努力を必要とする大きな欠点です(必要なパッケージを見つけて、互換性を確認します。互換性がより高い可能性のある不適切なパッケージを選択することを検討します。最適なバージョンを選択し、それを3.2に更新します。日;その後、有用な何かを始めます)。
おそらく2012年半ばには、これは欠点にはなりません。
ファンボーイに反対投票されたと思います。開発者のディスカッション中に、高レベルの開発者チームも同じ結論に達しました。
1つの主要な意味での成熟とは、チームがテクノロジーを使用し、隠れたリスク(互換性の問題を含む)なしで非常に迅速に稼働できることを意味します。サードパーティpythonパッケージと多くのアプリはそうではありません今日の大部分のパッケージでは3.2で動作します。これにより、手元の問題を解決する代わりに、テクノロジ自体の統合、テスト、再実装の作業が増えます==成熟していないテクノロジ
2013年6月の更新:Python 3にはまだ成熟の問題があります。チームメンバーは必要なパッケージについて言及し、「2.6以外は例外です」(これらのケースの一部では、 veは、2.6でのみ2.6のみのパッケージを使用するようにlocalhostソケットを介して回避策を実装し、残りのツールは3.2のままです。MoinMoin、pure-python wikiもPython = 3。
Pythonのスコープはひどく壊れているため、Pythonでのオブジェクト指向プログラミングは非常に扱いにくくなっています。
Python=のアクセス修飾子は強制できません-適切に構造化され、モジュール化されたコードを書くことが困難になります。
これは@Masonの壊れたスコープの一部だと思います。この言語の一般的な大きな問題です。読みやすいコードの場合、スコープ内に何があり、どのようにあるべきか、どの時点でどのような値になるかを理解するのは非常に難しいようです。現在、Python言語。
「私たちはすべて大人に同意している」からといって、特に複雑なプロジェクトで作業しているときは、間違いを犯したり、強い構造の中でうまく機能したりしないという意味ではありません。インデントや無意味なアンダースコアでは十分ではないようです。 。
Pythonに関する私の不満:
マルチディスパッチは、確立されたシングルディスパッチタイプのシステムとうまく統合されておらず、あまりパフォーマンスが良くありません。
動的ロードは、POSIXのようなセマンティクスがメタデータ集約型の操作の破滅的なスローダウンにつながる並列ファイルシステムでの大きな問題です。 65kコアにPython(numpy、mpi4py、petsc4py、およびその他の拡張モジュールを含む)をロードしているだけで、25万コア時間を消費した同僚がいます(シミュレーションは、重要な新しい科学をもたらしました結果、それは価値がありましたが、1バレル以上のオイルを燃焼させてロードする場合は問題ですPython一度)。静的にリンクできないため、 libc-rtldにパッチを適用してdlopen
が一括ファイルシステムアクセスを実行するようにするなど、大規模なロード時間を合理的に取得します。
とにかく、pythonは4年間私の主な言語になりました。ファンボーイ、エリート主義者、または独占マニアであることは、python文化の一部ではありません。
私はpythonを支持しますが、私の頭に浮かぶ最初の欠点は、if myTest():
のようなステートメントをコメントアウトするときに、実行するブロック全体のインデントを変更する必要があることですCやJavaを使用する必要はありません。実際には、pythonでif節をコメント化する代わりに、次のようにコメントアウトし始めました: `if True:#myTest( )なので、次のコードブロックを変更する必要もありませんJavaおよびCはインデントに依存しないため、CおよびJavaでステートメントをコメントアウトしやすくなります。
しかし、それはいくつかの素晴らしい償還機能を持っています:
len(s)
〜__len__(self)
およびその他の「特別なメソッド」__add__
および__iadd__
ために +
および+=
)self
「不変性」が長所ではない。 AFAIKの数値、タプル、文字列は不変であり、その他すべて(つまりオブジェクト)は変更可能です。 ErlangやHaskellなど、すべてが不変である関数型言語と比較してください(デフォルトでは、少なくとも)。
ただし、不変性は本当に同時実行性*で本当に優れています。これはPythonの強みでもありません。そのため、少なくとも必然的です。
(* = nitpickersの場合:少なくとも部分的に並行である並行性を意味します。Pythonは、不変性がそれほど重要ではない「シングルスレッド」の並行性でも問題ありません。(はい、 FP愛好家は、同時実行性がなくても不変性が優れていることを知っています。))
明示的に並列の構成体が欲しいです。多くの場合、私が次のようなリスト内包を書くとき
[ f(x) for x in lots_of_sx ]
要素が処理される順序は気にしません。時々、私はそれらが返される順序を気にしさえしません。
私のfが純粋なPythonであるときにCPythonがうまく機能しない場合でも、このような動作を他の実装で使用するように定義できます。
Pythonには、主に 哲学的理由 のために、末尾呼び出しの最適化はありません。これは、大きな構造での末尾再帰はO(n)メモリを消費する可能性があり(保持されている不要なスタックのため)、O(1)メモリ。