2009-04-24 12 views
0

この問題を絞り込むのに少し時間がかかりましたが、Pythonがこの1つの目的を果たしているようです。誰かがなぜこれが起こっているのか、これを解決するために何ができるのかを誰かが説明できますか?Pythonモジュール/クラス変数出血

ファイル:ライブラリ/ testModule.py

class testClass: 

    myvars = dict() 

    def __getattr__(self, k): 
     if self.myvars.has_key(k): 
      return self.myvars[k] 

    def __setattr__(self, k, v): 
     self.myvars[k] = v 

    def __str__(self): 
     l = [] 
     for k, v in self.myvars.iteritems(): 
      l.append(str(k) + ":" + str(v)) 

     return " - ".join(l) 

test.py

from library import testModule 

#I get the same result if I instantiate both classes one after another 
c1 = testClass() 
c1.foo = "hello" 
c2 = testClass() 

print("c1: " + str(c1) + "\n") 
print("c2: " + str(c2) + "\n") 

出力:

c1: foo:hello 
c2: foo:hello 

私の最高の推測であることlibrary"__init__.py"ファイルを持っているので、モジュール全体がクラスオブジェクトのように読み込まれ、現在は永続オブジェクトの一部となっています..これはこの場合ですか?

+0

これはクラス/インスタンス変数の問題であり、モジュールとは関係がないため、質問のタイトルを改訂できますか? –

答えて

7

myvarsは、クラスのプロパティであり、インスタンスではありません。つまり、インスタンスc1から属性myvarsに属性を挿入すると、属性は具体的にはインスタンスc1ではなくクラスtestClassに関連付けられます。 c2は同じクラスのインスタンスであるため、同じ属性を持ちます。

あなたはこれを書き込むことによって、必要な動作を得ることができます:

class testClass: 
    def __init__(self): 
     self.myvars = dict() 

    def __getattr__(self, k): 
     if self.myvars.has_key(k): 
      return self.myvars[k] 

    def __setattr__(self, k, v): 
     self.myvars[k] = v 

    def __str__(self): 
     l = [] 
     for k, v in self.myvars.iteritems(): 
      l.append(str(k) + ":" + str(v)) 
     return " - ".join(l) 
+0

実際、__init __()にself.myvars = dict()を代入すると、再帰エラーが発生します。 Heh、私は解決策は、__setattr__を削除し、代わりに__dict__ varを使用することだと思います。 – Ian

+0

ああ、私は再帰の問題については考えなかった...あなたはそれを回避することができたが、実際には組み込みのvar __dict__を使う方が良いだろう。これはまさにそのためのものです。 –

+0

これはおそらく賢明です。しかし、再帰エラーを引き起こすのは__setattr__ではありません。 __setatrr__は、最初の行で自身を呼び出す__getattr__を呼び出します。 –

2

他の回答が正しいとポイントにしています。あなたの誤解があると思うことのいくつかを取り上げてみましょう。

私の最高の推測では、ライブラリは、「__init__.py」ファイルを持っているので、このような場合は...モジュール全体がクラスオブジェクトのようにロードされ、それが今で持続的なオブジェクトの一部になるということですか?

すべてのパッケージには__init__.pyというファイルがあります。何かをPythonパッケージにする必要があります。そのパッケージにはコードが含まれていてもいなくてもかまいません。それが実行されると保証されます。一般的なケースでは、パッケージ内の他のモジュールがどのように実行されるかは関係ありませんが、そこには本当にすてきなトリッキーを置くことは可能です。

モジュールとクラスがどのように機能するかについては、モジュールをクラスオブジェクトとして考えて、一度インスタンス化されることをお勧めします。ローダーはファイルを一度実行し、ファイルの最後にあるすべての変数、クラス定義、関数定義をモジュールの一部としてアクセスできます。

クラス内で宣言されている関数がメソッドに変換されるという主な例外はありますが、クラスをインスタンス化する特別なメソッドが1つあります。従って、testModuleは--myvarsを有する。 3つのオブジェクトはすべてユニークです。それらのインスタンスが複数存在することはありません。そして、has-a relathionshipは、 "module has-class object"または "class object has-class variable"のどちらを言っても、実際には多かれ少なかれ同じです。 GETATTRとそれのような他の方法を使用する方法について良い参考のため(の違いあなたが心配するべきではない実装の詳細であること。)

関連する問題