Python変数を使用する際に避けるべき3つのエラーについて簡単に説明します

4982 ワード

Pythonプログラミングではよくわけのわからないエラーが発生しますが、これは言語そのものの問題ではなく、言語そのものの特性を無視したことによるものです.今日はPython変数を使用する際に発生する3つの不思議なエラーを見てみましょう.これからプログラミングに注意してください.
Pythonプログラミングの実行時に初心者がエラーを犯しやすいことについては、ここでは説明しません.詳細は、Pythonが実行している17の初心者によくあるエラーのまとめを参照してください.
1、可変データ型は関数定義のデフォルトパラメータとする
これは正しいようですか?現在のページのリンクを検索したり、別の提供リストに追加したりするなど、小さな関数を書きました.

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)

2、可変データ型をクラス変数とする
これは上記の最後の間違いとよく似ています.次のコードを考えます.

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をインスタンス化した.一つのURLをaに、もう一つは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つの個別のリストが使用されます.
3、可変の分配エラー
この問題はしばらく私を困らせた.いくつかの変更を行い、別の可変データ型である辞書を使用します.

a ={'1':"one",'2':'two'}

今、この辞書を別の場所で使用し、初期データを完全に維持したいと仮定します.

b = a
b['3']='three'

簡単でしょう?
今、私たちが変えたくない辞書aを見てみましょう.

{'1':"one",'2':'two','3':'three'}

わあ、ちょっと待って、bを見てみましょうか.

{'1':"one",'2':'two','3':'three'}

待って、何?ちょっと散らかっていますが...他の可変タイプがこの場合に何が起こるかを思い出してみましょう.たとえば、メタグループです.

c =(2,3)
d = c
d =(4,5)

現在cは(2,3),dは(4,5)である.
この関数の結果は私たちが予想したとおりです.では、前の例ではいったい何が起こったのでしょうか.可変タイプを使用する場合、その動作はC言語のポインタに似ています.上のコードでは、b=aを、bがaの参照になることを意味します.いずれもPythonメモリ内の同じオブジェクトを指します.少し熟知しているように聞こえますか?それはこの問題が以前と似ているからだ.
リストでも同じことが起こりますか?はい.では、私たちはどのように解決しますか?これは非常に注意しなければならない.もし私たちが本当にリストをコピーして処理する必要があるなら、私たちはこのようにすることができます.

b = a[:]

これにより、リスト内の各オブジェクトの参照が遍歴され、コピーされ、新しいリストに配置されます.ただし、リスト内の各オブジェクトが可変である場合は、完全なコピーではなく参照を再度取得します.
1枚の紙にリストを並べるとします.従来の例では、A氏とB氏が同じ紙を見ていたことに相当する.もし誰かがこのリストを修正したら、二人とも同じ変化を見ることができます.参照をコピーすると、誰もが自分のリストを持っています.しかし、このリストには食べ物を探す場所が含まれていると仮定します.「冷蔵庫」がリストの最初の場合、コピーされても、両方のリストのエントリは同じ冷蔵庫を指します.だから、冷蔵庫がAに修正されて、中の大きなケーキを食べたら、Bもこのケーキが消えるのを見ます.ここには簡単な方法はありません.それを覚えてコードを書くときは、この問題を起こさない方法を使用します.
辞書は同じ方法で動作し、次の方法で高価なコピーを作成できます.

b = a.copy()

もう一度説明すると、これは新しい辞書を作成するだけで、元の同じエントリを指します.したがって、同じリストが2つあり、辞書aのキーが指す可変オブジェクトを修正すると、辞書bにもこれらの変化が見られる.
可変データ型のトラブルも強力な場所です.以上は実際の問題ではありません.発生を防ぐために注意しなければならない問題です.3番目のプロジェクトで高価なレプリケーション操作をソリューションとして使用する必要は99%ではありません.
まとめ
以上,Python変数を用いた場合に避けるべき3つのエラーのすべてについて述べたが,役に立つことを期待する.興味のある方は引き続き当駅:python探索のBaseHTTPServer-実現Webサーバ紹介、Python探索のSocketServer詳細などを参照してください.不足点があれば、コメントを歓迎します.友达の本駅に対する支持に感谢します!