はじめに
Pythonでリスト型の場合,
>>> for i in list:
... print(i)
で各要素にアクセスできます.
dict型の場合,
>>> for key in dict.keys:
... print("{}:{}".format(key,dict[key]))
で取得できます.
では例えば以下のようにクラス化されたものについてどのようにアクセスしたら良いでしょうか.
class Animal:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
pochi = Animal('pochi',18,'male')
このときポチの中身は
>>> vars(pochi)
{'name': 'pochi', 'age': 18, 'sex': 'male'}
となります.
このとき各要素にfor文を使ってシーケンシャルにアクセスしようとすると,
>>> for attr in vars(pochi):
... print(pochi[attr])
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: 'Animal' object is not subscriptable
となりエラーが出てしまいます.
print(pochi.name)
print(pochi.age)
print(pochi.sex)
とすると中身にアクセスできるのですが,いちいち指定するのは面倒ですし,なんとかdict型のようにfor文などでアクセスできないでしょうか.
結論
getattr()
という組み込み関数を使うことで解決します.
先程の例では
>>> for attr in vars(pochi):
... print("{}:{}".format(attr,getattr(pochi,attr)))
...
name:pochi
age:18
sex:male
となり辞書型と同様の扱いをすることができました.
もうちょっと詳しく
ここでgetattr()
について
https://docs.python.org/ja/3/library/functions.html#getattr
を参照すると
getattr(object, name[, default])
となっており,任意の第3引数が設定されいることがわかります.
これはもし第1引数に指定した名前の属性が存在しない場合,第3引数に指定したものが返されます.
例を使って確認してみましょう.
>>> attr = 'age'
>>> print("{}:{}".format(attr,getattr(pochi,attr)))
age:18
>>> attr = 'weight'
>>> print("{}:{}".format(attr,getattr(pochi,attr)))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Animal' object has no attribute 'weight'
>>> print("{}:{}".format(attr,getattr(pochi,attr,'No measured')))
weight:No measured
例では3つの場合について検討しました.
1つ目はattr
に設定されている値がpochi
に含まれている場合.
2つ目はattr = weight
とすることで設定されていない値が入力された場合.
3つ目はgetattr()
に第3引数としてNo measured
が記述されていたときの場合です.
通常の動作が行えている最中は問題ないのですが,2つ目の例ではAttributeError
が返されています.しかし3つ目の例で第3引数にNo measured
を記述した場合,AttributeError
ではなくNo measured
が返され,エラーが返されることなく動作していることがわかります.
以上のことから結論として,メソッドなどをシーケンシャルにアクセスしたいときはpochi.name
などのようにいちいちアクセスしなくてもgetattr()
を用いればfor文などですべての要素にアクセスできることがわかりました.
さらに詳しいことはリファレンスを見てください.
https://www.python.org/dev/peps/pep-0231/
追記
@shiracamusよりgetattr()
を使用しなくてもvars()
のみ使用することで同様の操作が可能ではないかとのご指摘頂きました.
今回の記事はgetattr()
を用いることで,例えば指定されたlist
型に格納された値のみを参照したい場合のことなども想定しているため,dict
型の特性などを極力使わず,できるだけ原始的な方法で属性値にアクセスできる方法を紹介しています.
しかし,単一のオブジェクトに対して連続して属性値を取り出したい場合,vars()
とdict().keys()
の組み合わせによる方法が明快なため,その事例について追記いたします.原文はコメント欄を参照ください.
vars()
はdict()
型を戻り値としています.
またdict型の基本事項として,
>>> for name in vars(pochi):
... print(name)
...
name
age
sex
となり,list
型と同様にfor
文を設定してしまうと,dict().keys()
と同様の働きをしてしまい,辞書に登録されている名前を取り出してしまいます.
では,dict().items()
をfor
ループで取り出すとどのような値が出力されるでしょうか.
>>> for name in vars(pochi).items():
... print(name)
...
('name', 'pochi')
('age', 18)
('sex', 'male')
以上のようにtuple
型として辞書変数とその中身が取り出されていることがわかります.
これを応用することによって,getattr()
を使用しなくても
>>> for name, value in vars(pochi).items():
... print(f'{name}:{value}')
...
name:pochi
age:18
sex:male
のように書くことができます.