.
による属性の取得
class
文内で定義した、変数やメソッドといったオブジェクトの属性は、普通.
で取得すると思います。例えば次のようなクラスを定義したとします。
class Foo:
def __init__(self):
self.foo = "foo"
self.bar = "bar"
Foo
のインスタンスfoo
の属性foo
やbar
は.
で取得することができます。
>>> foo = Foo()
>>> foo.foo
'foo'
>>> foo.bar
'bar'
この.
による動作は特別な属性である__getattr__
や__getattribute__
メソッドを用いてカスタマイズすることができます。
__getattr__
によるカスタマイズ
__getattr__
を定義すると、.
で属性を取得しようとした時に、通常の名前検索をまず行って、それでも指定された属性が見つからない場合、__getattr__
が呼ばれ、返された値をその属性として返します。
次のクラスFoo
は、__getattr__
をメンバ変数foo
を常に返すように定義しています。
class Foo:
def __init__(self):
self.foo = "foo"
self.bar = "bar"
def __getattr__(self, name):
return self.foo
Foo
のインスタンスfoo
は、self.bar
というメンバ変数を持つので、foo.bar
では、self.bar
が返されますが、self.anything
というメンバ変数は無いのでself.__getattr__("anything")
が実行され、self.foo
(すなわち文字列"foo"
)が返されています。
>>> foo = Foo()
>>> foo.foo
'foo'
>>> foo.bar
'bar'
>>> foo.anything
'foo'
__getattribute__
によるカスタマイズ
__getattribute__
が定義されていた場合、.
で属性を取得しようとすると常にこのメソッドが呼ばれます。__getattribute__
の定義の中では、.
を用いてそのオブジェクトの属性を取得しようとすると、自分自身の__getattribute__
が再帰的に呼ばれてしまうため、それを避けるためにスーパークラスobject
の__getattribute__
を使用します。
class Bar:
def __init__(self):
self.foo = "foo"
self.bar = "bar"
def __getattribute__(self, name):
return object.__getattribute__(self, "foo")
次の実行結果を見るとわかるように、Bar
のインスタンスbar
は、self.bar
というメンバ変数を持っているにも関わらず、bar.bar
としても__getattribute__
によりself.foo
(すなわち文字列"foo"
)が返されています。
>>> bar = Bar()
>>> bar.foo
'foo'
>>> bar.bar
'foo'
>>> bar.anything
'foo'
組み込み関数getattr
とhasattr
組み込み関数getattr
とhasattr
は、__getattr__
や__hasattr__
でカスタマイズされた属性取得に基づきます。ですので、getattr
でオブジェクトの属性を取得するのと.
で取得するのは同じことです。上の例でのFoo
とBar
のインスタンスで確かめると出力はこうなります。
>>> getattr(foo, "bar")
'bar'
>>> getattr(bar, "bar")
'foo'
__getattr__
や__getattribute__
がどんな属性を指定しても値を返す(つまりAttributeError
が発生しない)のであれば、hasattr
は常にTrue
を返します。
>>> hasattr(foo, "anything")
True
>>> hasattr(bar, "anything")
True