[解決済み] リスト内包は、内包のスコープを越えても、名前を再束縛します。これは正しいのか?
質問
Comprehensions は、スコープと予期しない相互作用をしています。これは期待された動作なのでしょうか?
メソッドを持っている
def leave_room(self, uid):
u = self.user_by_id(uid)
r = self.rooms[u.rid]
other_uids = [ouid for ouid in r.users_by_id.keys() if ouid != u.uid]
other_us = [self.user_by_id(uid) for uid in other_uids]
r.remove_user(uid) # OOPS! uid has been re-bound by the list comprehension above
# Interestingly, it's rebound to the last uid in the list, so the error only shows
# up when len > 1
愚痴をこぼすかもしれませんが、これは残酷なエラーの元凶です。新しいコードを書いていると、たまに再バインドのために非常に奇妙なエラーを見つけることがあります -- それが問題だとわかっている今でも。リスト内包の temp vars の前には必ずアンダースコアを付ける、みたいなルールを作らないといけないのですが、それでも確実ではありません。
このランダムな時限爆弾が待っているという事実は、リスト内包の素晴らしい "使いやすさ"をすべて否定するようなものです。
どのように解決するのですか?
リスト内包は、Python 2ではループ制御変数をリークするが、Python 3ではリークしない。 Guido van Rossum (Pythonの作者)は次のように述べています。 説明 で説明しています。
私たちはまた、Python 3 では、リスト とジェネレータ 式の等価性を向上させるためです。Python 2 では、リスト を周囲のスコープにリークします。 変数を周囲のスコープにリークします。
x = 'before' a = [x for x in 1, 2, 3] print x # this prints '3', not 'before'
これはオリジナルの リスト内包の実装の成果です。 これはPythonの汚い秘密の1つです。 汚い秘密" の一つでした。これは を高速にするための意図的な妥協として始まりました。 これはリスト内包を目も眩むほど速くするための意図的な妥協として始まりました。 初心者にありがちな落とし穴ではありませんでしたが 初心者にありがちな落とし穴ではありませんでしたが、間違いなく人を刺す をたまに見かけます。ジェネレータ 式では、このようなことはできません。 ジェネレータ式は、ジェネレータを使用して実装されます。 ジェネレータ式はジェネレータを使用して実装され、その実行には は別の実行フレームを必要とします。 そのため、ジェネレータ式は は(特に短いシーケンスを反復する場合 特に短いシーケンスを反復する場合は)リスト内包よりも効率が リスト内包よりも効率が悪かったのです。
しかし、Python 3で、私たちは リスト内包の汚い小さな秘密("dirty little secret")を修正することにしました。 と同じ実装戦略を用いて、リスト内包の と同じ実装戦略で ジェネレータ式と同じ実装戦略を使うことにしました。したがって、Python 3では、上の例(print(x) :-)は print(x)を使うように修正したもの) は は '前' と表示され、リスト内包の 'x' が一時的に '前' となったことが証明されます。 はリスト内包で一時的に は一時的に影を落としますが、周囲のスコープの 'x' を上書きするわけではありません。 を上書きしないことを証明しています。
関連
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Jupyterノートブックでenv変数を設定する方法
-
[解決済み] Django のテストデータベースをメモリ上だけで動作させるには?
-
[解決済み] django.db.migrations.exceptions.InconsistentMigrationHistory
-
[解決済み] dict を txt ファイルに書き、それを読み取る?
-
[解決済み] PythonからSMTPを使用してメールを送信する
-
[解決済み] pandasのタイムゾーンに対応したDateTimeIndexを、特定のタイムゾーンに対応したナイーブなタイムスタンプに変換する。
-
[解決済み] PyQtアプリケーションのスレッド化。QtスレッドとPythonスレッドのどちらを使うか?
-
[解決済み] Python Empty Generator 関数
-
[解決済み] Pythonの文字列書式をリストで使う
-
[解決済み] Django filter queryset __in for *every* item in list