HOWTO · Python

Python で Object Has No Attribute エラーを修正する

このチュートリアルでは、Python の object has no attribute エラーについて説明します。

このページの内容

Pythonでは、ドットの前にあるオブジェクトで属性を検索できないと AttributeError が発生します。名前のスペルミス、別の型で定義された属性、または想定と異なる方法でオブジェクトが初期化されたことが原因として考えられます。たとえば、リストとNumPy配列は異なる型なので、一方で使える属性がもう一方でも使えるとは限りません。

Pythonの「オブジェクトに属性がない」エラーとは

items.size では、Pythonは items に割り当てられたオブジェクトに size という属性を問い合わせます。このエラーが示すのは、そのオブジェクトと見つからなかった名前です。その名前がPythonのどこにも存在しないという意味ではありません。コードを変更する前に、属性アクセスの対象となっているオブジェクトの型を確認してください。

属性が見つからない原因を調べる

エラーが発生する式の箇所から調べます。変数の型を出力するか確認し、使うつもりだったクラスやAPIの名前と照らし合わせて、スペルや大文字・小文字を確認してください。前の処理で値が別のオブジェクトに置き換わっていることもあります。たとえば、配列の代わりにリストが入っている場合です。

手早く調べるには、dir(value) を使うとオブジェクトで利用できる多くの名前を一覧できます。ただし、これはデバッグの手がかりであり、属性にアクセスできないことを完全に証明するものではありません。メタクラスの動作によって、dir() に表示されない属性が公開される場合があります。詳しくはPythonのメタクラスガイドを参照してください。

小さなクラスの例で、属性アクセスの対象を確認しましょう。User は name を定義していますが、別のクラスである Guest は定義していません。

class User:
    def __init__(self, name):
        self.name = name


class Guest:
    pass


person = User("Ada")
visitor = Guest()
print(person.name)
print(type(visitor).__name__)
try:
    visitor.name
except AttributeError:
    print("visitor has no name")

最初のアクセスが成功するのは、person が name を持つ User のインスタンスだからです。最後のアクセスでは、Guest のインスタンス visitor に name を問い合わせています。この検索で発生する AttributeError だけを対象にした例外処理が、説明メッセージを出力します。表示される「visitor has no name」は英語のままで、「visitor(訪問者)には名前がありません」という意味です。インスタンスで定義するメソッドでは、呼び出し時にPythonがインスタンスを渡せるよう、最初の引数に self を含める必要があります。

属性エラーを修正する

原因に合わせて修正します。名前の誤りを直す、意図したオブジェクトに対して属性を呼び出す、またはその属性やメソッドを提供すべきクラスで定義して初期化する、といった方法があります。名前を使えるようにするだけの目的でオブジェクトの型を変更しないでください。ほかのコードが元の型を前提としていると、型の変更後に別のエラーが起きることがあります。

通常どおり属性にアクセスできるようにするには、クラスとオブジェクトのデータを対応させます。

この例を実行してください。

class Account:
    def __init__(self, owner):
        self.owner = owner


account = Account("Mina")
print(account.owner)
Mina

任意の属性を安全に扱う

属性が本当に任意の場合は、hasattr(value, "name") で属性検索が成功するか確認できます。属性の有無によって処理を分ける場合は、条件分岐のガードとして使ってください。代替値が必要なら、getattr(value, "name", default) は属性検索で AttributeError が発生したときに既定値を返します。setattr() は属性を割り当てる関数であり、検索時の代替値を指定するものではありません。

エラーを直接処理するほうが明確な場合は、失敗する可能性のある属性アクセスだけを try ブロックに入れ、その箇所で AttributeError を捕捉します。こうすれば、無関係なエラーを見逃さずに済みます。プログラムの残りの処理が安全に使える値を代替値として選んでください。プレースホルダーを使うのは、その値が今回の目的において「値がない」ことと同じ意味になる場合に限ります。