このクラスから取得したデフォルト値の引数を使用して、クラス内にメソッドを構築したいと思います。一般的に、いくつかのデータでフィルタリングを行います。クラス内には、通常、データのベクトルを渡すメソッドがあります。時々、ベクターがなく、シミュレートされたデータを取得します。特定のベクトルを渡さないたびに、デフォルトでシミュレーションデータを取得したいと思います。メソッド定義内で_a=self.vector
_と言う簡単な構造にすべきだと思いました。しかし、何らかの理由でエラー_NameError: name 'self' is not defined
_があります。簡略化された構造は次のとおりです。
_class baseClass(object): # This class takes an initial data or simulation
def __init__(self):
self.x = 1
self.y = 2
class extendedClass(baseClass): # This class does some filtering
def __init__(self):
baseClass.__init__(self)
self.z = 5
def doSomething(self, a=self.z):
self.z = 3
self.b = a
if __== '__main__':
a = extendedClass()
print a.__dict__
a.doSomething()
print a.__dict__
_
予想される出力は次のとおりです。
_{'y': 2, 'x': 1, 'z': 5}
{'y': 2, 'x': 1, 'z': 3, 'b': 5}
_
def doSomething(self, a=z):
としてデフォルトの割り当てを試みましたが、明らかにそれは決して機能しません。私が理解している限り、_self.z
_はこのスコープで表示され、デフォルト値として持っていても問題になりません。このエラーが発生した理由とその方法がわかりません。これはおそらく簡単な質問ですが、私はそれを理解しようとするか、すでにしばらくの間、不足なく解決策を見つけようとします。 similar 他の言語のみの質問を見つけました。
あなたの理解は間違っています。 self
は、それ自体がその関数定義のパラメーターであるため、その時点でスコープ内に存在する方法はありません。関数自体の範囲内にのみあります。
答えは、単に引数をNone
にデフォルト設定し、メソッド内でそれを確認することです。
def doSomething(self, a=None):
if a is None:
a = self.z
self.z = 3
self.b = a
簡単なサンプルモジュールのコードの逆アセンブリを次に示します。コードオブジェクトは、バイトコード、使用する定数と名前、ローカル変数の数、必要なスタックサイズなどに関するメタデータの読み取り専用コンテナーです。すべてのコードオブジェクトは定数としてコンパイルされることに注意してください。これらはコンパイル時に作成されます。ただし、オブジェクト_class A
_および_function test
_は、実行時にインスタンス化されます(たとえば、モジュールがインポートされるとき)。
クラスを作成するために、_BUILD_CLASS
_は名前_'A'
_、ベースTuple
_(object,)
_、およびクラス名前空間の属性を含むdict
を取ります。これは、type(name, bases, dict)
を呼び出して手動で型をインスタンス化するようなものです。 dict
を作成するには、コードオブジェクトA
から関数を作成して呼び出します。最後に、クラスオブジェクトは_STORE_NAME
_を介してモジュール名前空間に保存されます。
コードオブジェクトA
では、_self.z
_が_MAKE_FUNCTION
_の引数としてスタックにロードされます。バイトコードop _LOAD_NAME
_は、現在のローカル(つまり、定義されているクラスの名前空間)、モジュールグローバル、およびビルトインでself
を検索します。 self
がグローバルスコープまたはビルトインスコープで定義されていない場合、これは明らかに失敗します。それは明らかにローカルスコープで定義されていません。
ただし、成功した場合、関数は_(self.z,)
_属性として___defaults__
_を使用して作成され、ローカル名test
に保存されます。
_>>> code = compile('''
... class A(object):
... def test(self, a=self.z): pass
... ''', '<input>', 'exec')
>>> dis.dis(code)
2 0 LOAD_CONST 0 ('A')
3 LOAD_NAME 0 (object)
6 BUILD_Tuple 1
9 LOAD_CONST 1 (<code object A ...>)
12 MAKE_FUNCTION 0
15 CALL_FUNCTION 0
18 BUILD_CLASS
19 STORE_NAME 1 (A)
22 LOAD_CONST 2 (None)
25 RETURN_VALUE
>>> dis.dis(code.co_consts[1]) # code object A
2 0 LOAD_NAME 0 (__name__)
3 STORE_NAME 1 (__module__)
3 6 LOAD_NAME 2 (self)
9 LOAD_ATTR 3 (z)
12 LOAD_CONST 0 (<code object test ...>)
15 MAKE_FUNCTION 1
18 STORE_NAME 4 (test)
21 LOAD_LOCALS
22 RETURN_VALUE
_
@ uselpa: Pastebinの例(2.x用に書き換えられました):
_>>> code = compile('''
... default = 1
... class Cl(object):
... def __init__(self, a=default):
... print a
... Cl()
... default = 2
... Cl()
... ''', '<input>', 'exec')
>>> dis.dis(code)
2 0 LOAD_CONST 0 (1)
3 STORE_NAME 0 (default)
3 6 LOAD_CONST 1 ('Cl')
9 LOAD_NAME 1 (object)
12 BUILD_Tuple 1
15 LOAD_CONST 2 (<code object Cl ...>)
18 MAKE_FUNCTION 0
21 CALL_FUNCTION 0
24 BUILD_CLASS
25 STORE_NAME 2 (Cl)
6 28 LOAD_NAME 2 (Cl)
31 CALL_FUNCTION 0
34 POP_TOP
7 35 LOAD_CONST 3 (2)
38 STORE_NAME 0 (default)
8 41 LOAD_NAME 2 (Cl)
44 CALL_FUNCTION 0
47 POP_TOP
48 LOAD_CONST 4 (None)
51 RETURN_VALUE
_
ご覧のとおり、クラスオブジェクトCl
(および関数オブジェクト___init__
_)は、インスタンス化されてローカル名_'Cl'
_に一度だけ保存されます。モジュールは実行時に連続して実行されるため、その後に名前default
を再バインドしても、___init__
_のデフォルト値には影響しません。
以前にコンパイルされたコードと新しいデフォルト値を使用して、新しい関数を動的にインスタンス化できます。
_>>> default = 1
>>> class Cl(object):
... def __init__(self, a=default):
... print a
...
>>> from types import FunctionType
>>> default = 2
>>> Cl.__init__ = FunctionType(
... Cl.__init__.__code__, globals(), '__init__', (default,), None)
>>> c = Cl()
2
_
これは、___init__.__code__
_から既にコンパイルされたコードオブジェクトを再利用して、新しい___defaults__
_タプルで関数を作成します。
_>>> Cl.__init__.__defaults__
(2,)
_
デフォルト引数は、定義が実行されるときに一度だけ評価されます。代わりに、これを行います:
def doSomething(self, a=None):
if a is None:
a = self.z
self.z = 3
self.b = a
http://docs.python.org/release/3.3.0/tutorial/controlflow.html#more-on-defining-functions もご覧ください。
これにより、self.z
if a
がNone
/False
/empty_value
:
def doSomething(self, a=None):
self.z = 3
self.b = (a or self.z)