Python は非常に表現力豊かな言語です。これは、作業を迅速に完了するのに役立つ巨大な標準ライブラリと多くの組み込みモジュールを提供します。しかし、多くの人は、Python が提供する機能に迷ったり、標準ライブラリを最大限に活用できなかったり、1 行のスクリプトに重点を置きすぎたり、Python の基本構造を誤解したりする可能性があります。この記事は、初心者の Python 開発者が陥る可能性のあるいくつかの落とし穴のリストであり、すべてを網羅しているわけではありません。
1. Python のバージョンがわかりません
これは StackOverflow で繰り返される質問です。多くの人は、あるバージョンで完全に動作するコードを作成できますが、システムには別のバージョンの Python がインストールされています。使用している Python のバージョンを必ず確認してください。
以下のコードを通じて Python のバージョンを確認できます:
[pythontab@testServer]$ python --version Python 2.7.10 [pythontab@testServer]$ python --V Python 2.7.10
上記の両方の方法が可能です
2. バージョン マネージャーを使用しないでください
pyenv はさまざまな Python バージョンを管理するための優れたツールですが、残念ながら、*nix システムでのみ動作します。 Mac システムでは、brew install pyenv 経由で簡単にインストールできます。Linux では、自動インストーラーもあります。
3. 一行プログラムに夢中
多くの人が一行プログラムによってもたらされる興奮に熱中しています。たとえ 1 行のソリューションが複数行のソリューションより効率的でなかったとしても、彼らはそれを自慢します。
Python におけるワンライナーは、本質的には複数の式による複雑な導出を意味します。例:
l = [m for a, b in zip(this, that) if b.method(a) != b for m in b if not m.method(a, b) and reduce(lambda x, y: a + y.method(), (m, a, b))]
正直に言うと、上記の例は私が作ったものです。しかし、多くの人が同様のコードを書いているのを目にします。このようなコードは 1 週間後には理解できなくなります。単純にリストに要素を追加したり、条件に基づいて設定したりするなど、もう少し複雑なことを実行したい場合は、おそらく間違いを犯すでしょう。
単一行のコードは成果ではありません。 確かに、柔軟に見えるかもしれませんが、それは成果ではありません。家を掃除してクローゼットにすべてを詰め込むようなものだと想像してください。優れたコードは、クリーンで、読みやすく、効率的である必要があります。
4. 間違った方法でコレクションを初期化する
これは、不意を突かれる可能性がある、より微妙な問題です。集合内包表記はリスト内包表記によく似ています。
>>> { n for n in range(10) if n % 2 == 0 } {0, 8, 2, 4, 6} >>> type({ n for n in range(10) if n % 2 == 0 })
上記は集合導出の例です。コレクションはリストとコンテナのようなものです。違いは、セット内に重複する値が存在できず、順序付けされていないことです。セットの導出を見る人は、{} が空のセットを初期化すると誤解することがよくあります。しかし、そうではなく、空の辞書が初期化されます。
>>> {} {} >>> type({})
空のコレクションを初期化したい場合は、set() メソッドを呼び出すだけです。
>>> set() set() >>> type(set())
空のセットは set() で表されますが、いくつかの要素を含むセットは要素を囲む中括弧で表す必要があることに注意してください。
>>> s = set() >>> s set() >>> s.add(1) >>> s {1} >>> s.add(2) >>> s {1, 2}
set([1, 2]) と同様のものを期待しているため、これは直感に反します。
5. GIL の誤解
GIL (グローバル インタープリター ロック) は、Python プログラムでは常に 1 つのスレッドしか実行できないことを意味します。これは、スレッドを作成してそれを並行して実行したい場合に、それが実行されないことを意味します。 Python インタープリターの実際の仕事は、実行中の異なるスレッド間で迅速に切り替えることです。しかし、これは実際に何が起こるかを非常に簡単に説明したもので、実際はもっと複雑です。本質的に C 拡張機能であるさまざまなライブラリを使用するなど、並列実行の例が多数あります。ただし、Python コードを実行する場合、ほとんどの場合、並列実行されません。言い換えれば、Python のスレッドは Java や C++ のスレッドとは異なります。
多くの人は、これらが本物のスレッドであると言って、Python を擁護しようとするでしょう。これは確かに真実ですが、Python が期待とは異なる方法でスレッドを処理するという事実は変わりません。同じ状況が Ruby 言語にも存在します (Ruby にはインタプリタ ロックもあります)。
指定された解決策は、マルチプロセッシング モジュールを使用することです。マルチプロセッシング モジュールは、フォークの適切なオーバーレイである Process クラスを提供します。ただし、フォーク プロセスはスレッドよりもはるかに高価であるため、異なるプロセス間で相互に調整するために多くの作業を実行する必要があるため、毎回パフォーマンスの向上が見られるわけではありません。
ただし、この問題は Python のすべての実装に存在するわけではありません。たとえば、Python の実装の 1 つである PyPy-stm は、GIL を削除しようとしています (まだ不安定です)。 JVM (Jython) や CLR (IronPython) など、他のプラットフォーム上に構築された Python 実装にも GIL の問題はありません。
つまり、Thread クラスを使用するときは注意してください。得られるものはあなたが望むものではない可能性があります。
6. 古いスタイルのクラスを使用する
在Python 2中,有两种类型的类,分别为“旧式”类和“新式”类。如果你使用Python 3,那么你默认使用“新式”类。为了确保在Python2中使用“新式”类,你需要让你新创建的每一个类都继承object类,且类不能已继承了内置类型,例如int或list。换句话说,你的基类、类如果不继承其他类,就总是需要继承object类。
class MyNewObject(object): # stuff here
这些“新式”类解决一些老式类的根本缺陷,想要详细了解新式类和旧式类请参见《python新式类和旧式类区别》《python2中的__new__与__init__,新式类和经典类》。
7.按错误的方式迭代
对于这门语言的新手来说,下边的代码是非常常见的:
for name_index in range(len(names)): print(names[name_index])
在上边的例子中,没有必须调用len函数,因为列表迭代实际上要简单得多:
for name in names: print(name)
此外,还有一大堆其他的工具帮助你简化迭代。例如,可以使用zip同时遍历两个列表:
for cat, dog in zip(cats, dogs): print(cat, dog)
如果你想同时考虑列表变量的索引和值,可以使用enumerate:
for index, cat in enumerate(cats): print(cat, index)
在itertools中也有很多有用的函数供你选择。然而请注意,使用itertools函数并不总是正确的选择。如果itertools中的一个函数为你试图解决的问题提供了一个非常方便的解决办法,例如铺平一个列表或根据给定的列表创建一个其内容的排列,那就用它吧。但是不要仅仅因为你想要它而去适应你代码的一部分。
滥用itertools引发的问题出现的过于频繁,以至于在StackOverflow上一个德高望重的Python贡献者已经贡献他们资料的重要组成部分来解决这些问题。
8.使用可变的默认参数
我多次见到过如下的代码:
def foo(a, b, c=[]): # append to c # do some more stuff
永远不要使用可变的默认参数,可以使用如下的代码代替:
def foo(a, b, c=None): if c is None: c = [] # append to c # do some more stuff
与其解释这个问题是什么,不如展示下使用可变默认参数的影响:
>>> def foo(a, b, c=[]): ... c.append(a) ... c.append(b) ... print(c) ... >>> foo(1, 1) [1, 1] >>> foo(1, 1) [1, 1, 1, 1] >>> foo(1, 1) [1, 1, 1, 1, 1, 1]
同一个变量c在函数调用的每一次都被反复引用。这可能有一些意想不到的后果。
总结
这些只是相对来说刚接触Python的人可能会遇到的一些问题。然而请注意,可能会遇到的问题远非就这么些。然而另一些缺陷是人们像使用Java或C++一样使用Python,并且试图按他们熟悉的方式使用Python。