ホームページ バックエンド開発 Python チュートリアル Python プログラマーが犯しやすい 10 の間違い

Python プログラマーが犯しやすい 10 の間違い

Nov 23, 2016 pm 01:35 PM
python

勉強や仕事の過程に関係なく、人は間違いを犯します。 Python の構文はシンプルで柔軟ですが、注意しないと、初心者も経験豊富な Python プログラマーもつまずく可能性があります。この記事では、一般的な 10 の間違いをすべての人に共有します。必要な友人は参照してください。よくある間違い 1: 式を関数のデフォルト パラメーターとして誤って使用する

Python では、関数のパラメーターにデフォルト値を設定できます。 , そのため、このパラメータはオプションになります。これは優れた言語機能ですが、デフォルト値が変更可能な型である場合には、混乱を招く状況が生じる可能性もあります。次の Python 関数定義を見てみましょう:
>>> def foo(bar=[]): # bar の値が指定されていない場合は、デフォルトで []、
になります。 ... bar.append("baz") # しかし、このコード行が問題を引き起こすことが後でわかります。
... リターンバー

Python プログラマーが犯すよくある間違いは、関数が呼び出されるたびに、オプションのパラメーターに値が渡されなければ、オプションのパラメーターが指定された値に設定されることを当然のことと考えることです。 .デフォルト値。上記のコードでは、foo() 関数を繰り返し呼び出すと常に 'baz' が返されるはずだと思うかもしれません。デフォルトでは、foo() 関数が実行されるたびに (bar 変数の値が指定されていない)、bar が返されるからです。変数は [ ] (つまり、新しい空のリスト) に設定されます。

ただし、実際の実行結果は次のようになります:
>>> foo()
["baz"]
>>> foo()["baz", "baz"]
> ;>> foo()
["バズ"、"バズ"、"バズ"]

おかしくないですか? foo() 関数が呼び出されるたびに、新しい空のリストを作成するのではなく、デフォルト値「baz」が既存のリストに追加されるのはなぜですか?

答えは、オプションのパラメーターのデフォルト値の設定は、Python で 1 回だけ、つまり関数の定義時にのみ実行されるということです。したがって、foo() 関数が定義されたときのみ、bar パラメータはデフォルト値 (つまり、空のリスト) に初期化されますが、その後 foo() 関数が呼び出されるたびに、bar パラメータは引き続き初期化されます。そのリストの元の値で初期化されます。

もちろん、一般的な解決策は次のとおりです:
>>> def foo(bar=None):
... bar が None の場合: # または bar:
... bar = []
。 .. bar.append("baz")
... return bar
...
>>> foo()
["baz"]
>>> foo()
[" baz "]
> :
... x = 1
...
>>> クラス B(A):
... pass
...
>>> クラス C(A) ):
.. . pass
...
>>> print A.x, B.x, C.x
1 1 1

この結果は正常です。
>>> B.x = 2
>>> print A.x, B.x, C.x
1 2 1

まあ、結果は予想通りです。
>>> A.x = 3
>>> print A.x, B.x, C.x
3 2 3

Python 言語では、クラス変数はメソッドの解析順序に従います。解決命令、MRO)。したがって、上記のコードでは、クラス C には x 属性がないため、インタプリタはその基本クラスを探します (ただし、Python は多重継承をサポートしていますが、この例では、C の基本クラスは A のみです)。言い換えれば、C は A から独立した独自の x 属性を持たず、実際に A に属します。したがって、C.x を参照すると、実際には A.x を参照します。ここでの関係を適切に処理しないと、例の問題が発生します。
よくある間違い 3: 例外ブロック (例外ブロック) のパラメーターの誤った指定

次のコードを見てください:
>>> try:
... l = ["a", "b"]
... int(l[2])
... ValueError、IndexError を除く: # 両方の例外をキャッチするには、そうですか?
... pass
...
Traceback (most 最新の呼び出し最後):
File "< ;stdin>"、 の 3 行目
IndexError: リストのインデックスが範囲外です

このコードの問題は、Except ステートメントがこの方法での例外の指定をサポートしていないことです。 Python 2.x では、例外をさらに表示するには、変数 e を使用して例外をオプションの 2 番目のパラメーターにバインドする必要があります。したがって、上記のコードでは、Except ステートメントは IndexError 例外をキャッチせず、代わりに、発生した例外を IndexError という名前のパラメータにバインドします。

Except ステートメントで複数の例外を正しくキャッチするには、最初のパラメーターをタプルとして指定し、キャッチする例外のタイプをタプルに記述する必要があります。また、移植性を向上させるには、Python 2 と Python 3 の両方でサポートされている as キーワードを使用します。
>>> try:
... l = ["a", "b"]
... int(l[2])
... e:
としての (ValueError, IndexError) を除く. pass
...
>>>
よくある間違い 4: Python の変数名解析の誤った理解

Python の変数名解析は、いわゆる LEGB 原則に従います。つまり、「L: ローカル スコープ」 ; E: 上位構造の def または lambda のローカル スコープ; G: グローバル スコープ; B: 組み込みスコープ (ローカル、エンクロージング、グローバル、ビルトイン) の順に検索します。シンプルに見えませんか?ただし、実際には、この原則が適用される方法にはいくつかの特別な特徴があります。これに関して言えば、次のよくある Python プログラミング エラーについて言及する必要があります。以下のコードを見てください:
>>> x = 10
>>> def foo():
... ;> foo()
Traceback (最新の呼び出し):
ファイル「、1 行目、
ファイル「」、2 行目、foo
UnboundLocalError: ローカル変数 'x' が代入前に参照されました

何が問題だったのでしょうか?

上記のエラーは、特定のスコープ内の変数に値を割り当てると、その変数が Python インタプリタによって自動的にスコープのローカル変数とみなされ、上位スコープ内の同じ名前の変数を置き換えるために発生します。変数。

だからこそ、最初はうまくいったコードが表示されますが、関数内に代入ステートメントを追加した後、UnboundLocalError が発生するのは、多くの人が驚くのも不思議ではありません。

Python プログラマーは、リストを扱うときに特にこの罠に陥る可能性があります。

次のコード例を見てください:
>>> lst = [1, 2, 3]
>>> def foo1():
... lst.append(5) # Notここで質問
>>> foo1()
>>> [1, 2, 3, 5]
>>>
>>> def foo2():
... lst += [5] # ... しかし、ここで何かが間違っています!
...
>>> トレースバック (ほとんど最近の呼び出し last):
ファイル「、1 行目、
ファイル「、2 行目、foo 内
UnboundLocalError: local代入前に変数「lst」が参照されました

え?関数 foo1 は正常に実行されるのに、foo2 でエラーが発生するのはなぜですか?

答えは前の例と同じですが、もう少しわかりにくいです。 foo1 関数は lst 変数に値を割り当てませんが、foo2 は値を割り当てます。 lst += [5] は lst = lst + [5] の単なる略語であることがわかります。このことから、foo2 関数が lst に値を割り当てようとしていることがわかります (したがって、ローカル変数とみなされます)。 Python インタプリタによる関数のスコープ)。ただし、lst に割り当てたい値は lst 変数自体に基づいています (この時点では、関数のローカル スコープ内の変数ともみなされます)。これは、変数がまだ定義されていないことを意味します。そのときエラーが発生しました。
よくある間違い 5: リストのトラバース中にリストを変更する

次のコードの問題は非常に明白です:
>>> od = lambda x : bool(x % 2)
>>>数値 = [範囲 (10) の n の場合]
> for i in range(len(数値)):
... 奇数の場合(数値[i]):
... del 数値[ i ] # 問題: 反復処理中にリストから項目を削除しています
...
トレースバック (最新の呼び出しは最後):
ファイル ""、2 行目、 内です
IndexError : リストのインデックスが範囲外です

反復処理中にリストまたは配列から要素を削除することは、経験豊富な Python 開発者なら誰でも知っていることです。ただし、上記の例は明白ですが、経験豊富な開発者は、より複雑なコードを作成するときにうっかり同じ間違いを犯す可能性があります。

幸いなことに、Python 言語には多くのエレガントなプログラミング パラダイムが組み込まれており、正しく使用すればコードを大幅に簡素化できます。コードを簡素化することのもう 1 つの利点は、リストを走査するときに要素を削除するエラーが発生する可能性が低くなることです。これを実現できるプログラミング パラダイムの 1 つはリスト内包表記です。さらに、リスト内包表記は、この問題を回避するのに特に役立ちます。
>>> od = lambda x : bool(x % 2)
>>> ; 数値 = [n の範囲 (10)]
>>> 数値[:] = [奇数でない場合は n の n] # ああ、素晴らしいですね
>> ; > 数値
[0, 2, 4, 6, 8]
よくある間違い 6: Python がクロージャで変数をバインドする方法を理解していない
>>>
... return [lambda x : i * x for i in range(5)]
>>> create_multipliers():
... print multiplier(2)
...

出力結果は次のようになると思います:

しかし、実際の出力結果は次のようになります:

ショックです!

この結果は、主に Python の遅延バインディング メカニズムが原因で発生します。つまり、クロージャ内の変数の値は、内部関数が呼び出されたときにのみクエリされます。したがって、上記のコードでは、create_multipliers() によって返された関数が呼び出されるたびに、変数 i の値が近くのスコープで検索されます (その時点までにループは終了しているため、最終的に変数 i が割り当てられます)値は 4)。

この一般的な Python の問題を解決するには、いくつかのハックを使用する必要があります:
>>> def create_multipliers():
... return [lambda x, i=i : i * x for i in range (5) )]
...
>>> create_multipliers():
... print multiplier(2)
...
0
2
4
6
8

注意してください!ここではデフォルトのパラメーターを使用して、このラムダ匿名関数を実装します。エレガントだと思う人もいるかもしれないし、賢いと思う人もいるかもしれないし、嘲笑する人もいるかもしれない。ただし、Python プログラマーであれば、とにかくこのソリューションについて知っておく必要があります。
よくある間違い 7: モジュール間の循環依存関係

以下に示すように、相互に参照する 2 つのファイル a.py と b.py があるとします。

a.py ファイル ファイル内のコード:
import b
def f():
return b. まず、a.py モジュールをインポートしてみます。

コードは正常に実行されます。もしかしたらこれは予想外かも知れません。結局のところ、ここには循環参照の問題があるので、問題があるはずですよね?

その答えは、循環参照が存在するだけでは問題が発生するわけではないということです。モジュールがすでに参照されている場合、Python はそのモジュールが再度参照されるのを防ぐことができます。ただし、各モジュールが他のモジュールによって定義された関数または変数に間違ったタイミングでアクセスしようとすると、問題が発生する可能性があります。

それでは例に戻りますが、a.py モジュールをインポートするとき、それが b.py モジュールを参照しても問題はありません。これは、b.py モジュールが参照されるときに a.py モジュールにアクセスする必要がないためです。 py モジュールで定義された変数または関数。 b.py モジュール内のモジュール a への唯一の参照は、モジュール a の foo() 関数の呼び出しです。ただし、その関数呼び出しは g() 関数内で発生し、g() 関数は a.py モジュールでも b.py モジュールでも呼び出されません。したがって、問題は発生しません。

しかし、(つまり、事前に a.py モジュールを参照せずに) b.py モジュールをインポートしようとするとどうなるでしょうか:
>>> import b
Traceback (most 最新の呼び出し最後):
File "< ;stdin>"、 の 1 行目
のファイル「b.py」、1 行目
import a
ファイル "a.py"、<の 6 行目;module>
print f()
ファイル "a.py"、4 行目、f
return b.x
AttributeError: 'module' オブジェクトには属性 'x' がありません

おっと。状況は良くありません!ここでの問題は、b.py をインポートするプロセスで、a.py モジュールを参照しようとし、a.py モジュールが foo() 関数を呼び出し、その後 b.x 変数にアクセスしようとすることです。ただし、この時点では b.x 変数が定義されていないため、AttributeError 例外が発生しました。

この問題を解決する非常に簡単な方法があります。それは、単に b.py モジュールを変更し、g() 関数内で a.py のみを参照することです:
x = 1
def g():
import a #これは g() が呼び出されたときにのみ評価されます
print a.f()

ここで b.py モジュールをインポートしても問題はありません:
>>> import b
>>> b.g()
1 # モジュール 'a' が最後に 'print f()' を呼び出したため、初めて出力されました
1 # 2 回目に出力されました。これは 'g' への呼び出しです
よくある間違い 8: モジュールの名前付けとPython 標準ライブラリのモジュール名の競合

Python 言語の大きな利点の 1 つは、独自の強力な標準ライブラリです。ただし、このため、細心の注意を払わないと、モジュールに Python 独自の標準ライブラリ モジュールと同じ名前を付ける可能性があります (たとえば、コード内に email.py というモジュールがある場合、これは競合します) Python 標準ライブラリの同じ名前のモジュールと)

これは、難しい問題を引き起こす可能性があります。たとえば、モジュール A をインポートするときに、モジュール A が Python 標準ライブラリのモジュール B を参照しようとすると、同じ名前のモジュール B がすでに存在するため、モジュール A は独自のコードではなく、誤ってモジュール B を参照します。 Python標準ライブラリのモジュールB。これは重大な間違いの原因にもなります。

したがって、Python プログラマは、Python 標準ライブラリ モジュールと同じ名前を使用しないように特に注意する必要があります。結局のところ、上流モジュールの名前を変更する PEP 提案を提案して提案を通過させるよりも、独自のモジュールの名前を変更する方がはるかに簡単です。
よくある間違い 9: Python 2 と Python 3 の違いを解決できない

次のコードがあるとします:
import sys
def bar(i):
if i == 1:
raise KeyError(1)
if i == 2:
Raise ValueError(2)
def bad():
e = None
try:
bar(int(sys.argv[1]))
ただし KeyError as e:
print('key error ' )
e:
print('value error')
print(e)
bad()


の ValueError を除く Python 2 の場合、コードは通常通り実行されます:
$ python foo.py 1
key error
1
$ python foo.py 2
value error
2

しかし、今度は Python 3 に切り替えて、もう一度実行しましょう:
$ python3 foo.py 1
key error
Traceback (most 最近の呼び出し最後):
File " foo.py"、19 行目、 内です
bad()
ファイル "foo.py"、17 行目、bad
print(e)
UnboundLocalError: 割り当て前にローカル変数 'e' が参照されました

一体何が起こっているの?ここでの「問題」は、Python 3 では、例外ブロックのスコープ外では例外オブジェクトにアクセスできないことです。 (この設計の理由は、そうしないと、ガベージ コレクターが実行され、参照がメモリからクリアされるまで、その参照ループがスタック フレームに残るためです。)

この問題を回避する 1 つの方法は、例外オブジェクトへの参照を維持することです。例外オブジェクトにアクセスできるように、Except コード ブロックのスコープ外にあります。次のコードはこのメソッドを使用しているため、Python 2 と Python 3 の出力結果は一貫しています:
import sys
def bar(i):
if i == 1:
raise KeyError(1)
if i == 2:
Raise ValueError(2)
def Good():
例外 = None
try:
bar(int(sys.argv[1]))
KeyError as e:
例外 = e
print ('キーエラー')
ValueError を除く e:
例外 = e
print('value error')
print(例外)
good()


Python 3 でコードを実行します:
$ python3 foo.py 1
key error
1
$ python3 foo.py 2
値エラー
2

素晴らしい!
よくある間違い 10: del メソッドの間違った使用

mod.py ファイルに次のコードを記述するとします:
import foo
class Bar(object):
...
def __del__(self):
foo。 cleanup(self.myhandle)

では、another_mod.py ファイルで次の操作を実行します。
import mod
mybar = mod.Bar()


another_mod.py モジュールを実行すると、AttributeError 例外が発生します。

なぜですか?インタプリタが終了すると、モジュールのグローバル変数が None に設定されるためです。したがって、上記の例では、__del__ メソッドが呼び出される前に foo が None に設定されています。

このやや難しい Python プログラミングの問題を解決するには、方法の 1 つは atexit.register() メソッドを使用することです。この場合、プログラムの実行が完了すると (つまり、プログラムが正常に終了すると)、インタープリターが閉じる前に、指定したハンドラーが実行されます。

上記のメソッドを適用した後、変更された mod.py ファイルは次のようになります:
import foo
import atexit
def cleanup(handle):
foo.cleanup(handle)
class Bar(object):
def __init__( self):
...
atexit.register(cleanup, self.myhandle)


この実装は、プログラムが正常に終了したときに必要なクリーンアップ関数をクリーンに呼び出すことをサポートします。明らかに、上記の例では、foo.cleanup 関数が self.myhandle にバインドされたオブジェクトの処理方法を決定します。

概要

Python は、作業効率を大幅に向上させる多くのプログラミング メカニズムとパラダイムを提供する強力で柔軟なプログラミング言語です。しかし、他のソフトウェア ツールや言語と同様、その言語の機能に対する理解や評価が限られている場合は、恩恵を受けるどころか、妨げられることがあります。ことわざにあるように、「十分に知っていると考えると、自分や他の人が危険にさらされる可能性があります。

Python 言語の微妙な点、特にこの記事で挙げた 10 のよくある間違いについてよく理解しておくと、Python を使用するのに役立ちます。」よくある間違いを回避しながら効果的に言語を習得できます

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

PSが荷重を見せ続ける理由は何ですか? PSが荷重を見せ続ける理由は何ですか? Apr 06, 2025 pm 06:39 PM

PSの「読み込み」の問題は、リソースアクセスまたは処理の問題によって引き起こされます。ハードディスクの読み取り速度は遅いか悪いです。CrystaldiskInfoを使用して、ハードディスクの健康を確認し、問題のあるハードディスクを置き換えます。不十分なメモリ:高解像度の画像と複雑な層処理に対するPSのニーズを満たすためのメモリをアップグレードします。グラフィックカードドライバーは時代遅れまたは破損しています:ドライバーを更新して、PSとグラフィックスカードの間の通信を最適化します。ファイルパスが長すぎるか、ファイル名に特殊文字があります。短いパスを使用して特殊文字を避けます。 PS独自の問題:PSインストーラーを再インストールまたは修理します。

PSが開始されたときにロードの問題を解決する方法は? PSが開始されたときにロードの問題を解決する方法は? Apr 06, 2025 pm 06:36 PM

ブートがさまざまな理由によって引き起こされる可能性がある場合、「読み込み」に巻き込まれたPS:腐敗したプラグインまたは競合するプラグインを無効にします。破損した構成ファイルの削除または名前変更。不十分なプログラムを閉じたり、メモリをアップグレードしたりして、メモリが不十分であることを避けます。ソリッドステートドライブにアップグレードして、ハードドライブの読み取りをスピードアップします。 PSを再インストールして、破損したシステムファイルまたはインストールパッケージの問題を修復します。エラーログ分析の起動プロセス中にエラー情報を表示します。

PSがファイルを開いたときにロードの問題を解決する方法は? PSがファイルを開いたときにロードの問題を解決する方法は? Apr 06, 2025 pm 06:33 PM

「ロード」は、PSでファイルを開くときに発生します。理由には、ファイルが大きすぎるか破損しているか、メモリが不十分で、ハードディスクの速度が遅い、グラフィックカードドライバーの問題、PSバージョンまたはプラグインの競合が含まれます。ソリューションは、ファイルのサイズと整合性を確認し、メモリの増加、ハードディスクのアップグレード、グラフィックカードドライバーの更新、不審なプラグインをアンインストールまたは無効にし、PSを再インストールします。この問題は、PSパフォーマンス設定を徐々にチェックして使用し、優れたファイル管理習慣を開発することにより、効果的に解決できます。

PSが常にロードされていることを常に示しているときに、ロードの問題を解決する方法は? PSが常にロードされていることを常に示しているときに、ロードの問題を解決する方法は? Apr 06, 2025 pm 06:30 PM

PSカードは「ロード」ですか?ソリューションには、コンピューターの構成(メモリ、ハードディスク、プロセッサ)の確認、ハードディスクの断片化のクリーニング、グラフィックカードドライバーの更新、PS設定の調整、PSの再インストール、優れたプログラミング習慣の開発が含まれます。

インストール後にMySQLの使用方法 インストール後にMySQLの使用方法 Apr 08, 2025 am 11:48 AM

この記事では、MySQLデータベースの操作を紹介します。まず、MySQLWorkBenchやコマンドラインクライアントなど、MySQLクライアントをインストールする必要があります。 1. mysql-uroot-pコマンドを使用してサーバーに接続し、ルートアカウントパスワードでログインします。 2。CreatedAtaBaseを使用してデータベースを作成し、データベースを選択します。 3. createTableを使用してテーブルを作成し、フィールドとデータ型を定義します。 4. INSERTINTOを使用してデータを挿入し、データをクエリし、更新することでデータを更新し、削除してデータを削除します。これらの手順を習得することによってのみ、一般的な問題に対処することを学び、データベースのパフォーマンスを最適化することでMySQLを効率的に使用できます。

PSフェザーリングは、遷移の柔らかさをどのように制御しますか? PSフェザーリングは、遷移の柔らかさをどのように制御しますか? Apr 06, 2025 pm 07:33 PM

羽毛の鍵は、その漸進的な性質を理解することです。 PS自体は、勾配曲線を直接制御するオプションを提供しませんが、複数の羽毛、マッチングマスク、および細かい選択により、半径と勾配の柔らかさを柔軟に調整して、自然な遷移効果を実現できます。

MySQLインストール後にデータベースのパフォーマンスを最適化する方法 MySQLインストール後にデータベースのパフォーマンスを最適化する方法 Apr 08, 2025 am 11:36 AM

MySQLパフォーマンスの最適化は、インストール構成、インデックス作成、クエリの最適化、監視、チューニングの3つの側面から開始する必要があります。 1。インストール後、INNODB_BUFFER_POOL_SIZEパラメーターやclose query_cache_sizeなど、サーバーの構成に従ってmy.cnfファイルを調整する必要があります。 2。過度のインデックスを回避するための適切なインデックスを作成し、説明コマンドを使用して実行計画を分析するなど、クエリステートメントを最適化します。 3. MySQL独自の監視ツール(ShowProcessList、ShowStatus)を使用して、データベースの健康を監視し、定期的にデータベースをバックアップして整理します。これらの手順を継続的に最適化することによってのみ、MySQLデータベースのパフォーマンスを改善できます。

PSカードがロードインターフェイスにある場合はどうすればよいですか? PSカードがロードインターフェイスにある場合はどうすればよいですか? Apr 06, 2025 pm 06:54 PM

PSカードの読み込みインターフェイスは、ソフトウェア自体(ファイルの破損またはプラグインの競合)、システム環境(ドライバーまたはシステムファイルの破損)、またはハードウェア(ハードディスクの破損またはメモリスティックの障害)によって引き起こされる場合があります。まず、コンピューターリソースで十分かどうかを確認し、バックグラウンドプログラムを閉じ、メモリとCPUリソースをリリースします。 PSのインストールを修正するか、プラグインの互換性の問題を確認してください。 PSバージョンを更新またはフォールバックします。グラフィックカードドライバーをチェックして更新し、システムファイルチェックを実行します。上記の問題をトラブルシューティングする場合は、ハードディスク検出とメモリテストを試すことができます。

See all articles