.による属性の取得
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