ホームページ >バックエンド開発 >Python チュートリアル >Python 変数の使用におけるよくある間違いの紹介
実際、これは言語自体の問題ではなく、言語自体のいくつかの特性を無視したことが原因で発生することがよくあります。今日は、Python の使用時に発生する 3 つの信じられないエラーを見ていきます。今後のプログラミングでは変数に注意してください。
これは正しいと思いますか?たとえば、現在のページでリンクを検索し、必要に応じてそれを別の提供されたリストに追加する小さな関数を作成します。
def search_for_links(page, add_to=[]): new_links = page.search_for_links() add_to.extend(new_links) return add_to
表面的には、これは完全に通常の Python コードのように見えますが、実際その通りで、動作します。ただし、問題があります。 add_to パラメータにリストを指定すると、期待どおりに機能します。しかし、デフォルト値を使用すると、魔法のようなことが起こります。
次のコードを試してください:
def fn(var1, var2=[]): var2.append(var1) print(var2) fn(3) fn(4) fn(5)
おそらく、次のコードが表示されると思うでしょう:
[3] [4] [5]
しかし、実際に表示されるのは次のとおりです:
[3] [3,4] [3,4,5]
なぜですか?ご覧のとおり、毎回同じリストが使用されるのですが、なぜこのような出力になるのでしょうか。 Python では、このような関数を作成すると、このリストが関数定義の一部としてインスタンス化されます。関数が実行されるとき、毎回インスタンス化されるわけではありません。これは、新しいオブジェクトを提供しない限り、この関数は常にまったく同じリスト オブジェクトを使用することを意味します:
fn(3,[4]) [4,3]
答えはまさに私たちが考えたものです。この結果を取得する正しい方法は次のとおりです:
def fn(var1, var2=None): ifnot var2: var2 =[] var2.append(var1)
または最初の例では:
def search_for_links(page, add_to=None): ifnot add_to: add_to =[] new_links = page.search_for_links() add_to.extend(new_links) return add_to
これにより、関数が実行されるたびにリストのインスタンス化が発生するように、モジュールがロードされるときにインスタンス化されたコンテンツが削除されます。タプル、文字列、整数などの不変のデータ型の場合は、この状況を考慮する必要がないことに注意してください。これは、次のようなコードが非常に実現可能であることを意味します:
def func(message="my message"): print(message)
これは、上記の最後のエラーと非常によく似ています。次のコードを考えてみましょう:
class URLCatcher(object): urls =[] def add_url(self, url): self.urls.append(url)
このコードはまったく正常に見えます。 URL を格納するオブジェクトがあります。 add_url メソッドを呼び出すと、指定された URL がストレージに追加されます。かなり正しく見えますよね?実際の動作を見てみましょう:
a =URLCatcher() a.add_url('http://www.google.com') b =URLCatcher() b.add_url('http://www.pythontab.com') print(b.urls) print(a.urls)
結果:
['http://www.google.com','http://www.pythontab.com'] ['http://www.google.com','http://www.pythontab.com']
待って、何が起こっているのでしょうか? !それは私たちが考えたことではありません。 2 つの別々のオブジェクト a と b をインスタンス化します。 1 つの URL を a に与え、別の URL を b に与えます。なぜこれら 2 つのオブジェクトに 2 つの URL があるのでしょうか?
これは最初のエラー例と同じ問題です。クラス定義が作成されると、URL リストがインスタンス化されます。このクラスのすべてのインスタンスは同じリストを使用します。これが役立つ場合もありますが、ほとんどの場合はやりたくないでしょう。オブジェクトごとに個別のストアが必要です。これを行うには、コードを次のように変更します。
class URLCatcher(object): def __init__(self): self.urls =[] def add_url(self, url): self.urls.append(url)
これで、オブジェクトが作成されると、URL リストがインスタンス化されます。 2 つの別々のオブジェクトをインスタンス化すると、それぞれ 2 つの別々のリストが使用されます。
この問題は私をしばらく悩ませました。いくつかの変更を加えて、別の可変データ型である辞書を使用してみましょう。
a ={'1':"one",'2':'two'}
さて、この辞書を元のデータをそのまま保持したまま別の場所で使用したいとします。
rree簡単ですよね?
さて、変更したくない元の辞書 a を見てみましょう:
b = a b['3']='three'
ちょっと待って、b を見てみましょう。
えーちょっと待って、何?少し面倒です...バックアップして、タプルなど他の不変型を使用した場合に何が起こるかを見てみましょう:
{'1':"one",'2':'two','3':'three'}
今、c は (2, 3)、d は (4, 5) です。
この関数の結果は予想どおりです。では、前の例では正確に何が起こったのでしょうか?可変型を使用する場合、それは C のポインターのように動作します。上記のコードでは b = a としていますが、実際の意味は、b が a の参照になるということです。これらはすべて、Python メモリ内の同じオブジェクトを指します。おなじみですね?それは、この質問が前の質問と似ているからです。
リストでも同じことが起こりますか?はい。では、どうすれば解決できるのでしょうか?これは非常に慎重に行う必要があります。処理のためにリストをコピーする必要がある場合は、次のようにすることができます:
{'1':"one",'2':'two','3':'three'}
これは、リスト内の各オブジェクトの参照をループしてコピーし、新しいリストに置きます。ただし注意してください。リスト内のすべてのオブジェクトが変更可能である場合、完全なコピーではなく、それらへの参照が再度取得されることになります。
紙にリストを作成したとします。元の例では、A と B が同じ紙を見ていることに相当します。 1 人がこのリストを変更すると、両方の人に同じ変更が表示されます。参考文献をコピーすると、全員が独自のリストを持つことになります。ただし、このリストには食べ物を見つける場所が含まれていると想定しています。 「refrigerator」がリストの最初にある場合、それがコピーされたとしても、両方のリストのエントリは同じ冷蔵庫を指すことになります。したがって、A が冷蔵庫を改造して、中の大きなケーキを食べた場合、B もケーキが消えるのを目にすることになります。ここを回避する簡単な方法はありません。このことを覚えておいて、この問題が発生しない方法でコードを記述してください。
字典以相同的方式工作,并且你可以通过以下方式创建一个昂贵副本:
b = a.copy()
再次说明,这只会创建一个新的字典,指向原来存在的相同的条目。因此,如果我们有两个相同的列表,并且我们修改字典 a 的一个键指向的可变对象,那么在字典 b 中也将看到这些变化。
可变数据类型的麻烦也是它们强大的地方。以上都不是实际中的问题;它们是一些要注意防止出现的问题。在第三个项目中使用昂贵复制操作作为解决方案在 99% 的时候是没有必要的。
以上がPython 変数の使用におけるよくある間違いの紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。