LoginSignup
1
2

More than 1 year has passed since last update.

【備忘録】Pythonでオブジェクトの属性値をfor文で取り出したいとき【getattr()の使い方】

Last updated at Posted at 2021-11-10

はじめに

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

のように書くことができます.

1
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2