※Qiitaにも同様の記事を公開しております。コードなどはこちらのほうが見やすいかもしれません。

https://qiita.com/VDiUZnM1hUIzKvb/items/4d18ca1d781ed6ff2b2f


はじめに

機械学習を始めとし、プログラミングに対する興味は年々高まっています。特に、先人たちが作ったモジュールを使えるPythonは、トップクラスの成長率をもっています。

しかし、Pythonを活用する上で大きな障害となるのが「AttributeError」。Python使いなら誰もが通る道でしょう。

この記事では、以下に示す5つのAttributeError原因と対処法について説明します。

・属性名のスペルミス・誤字
・ファイル名とモジュール名が同じになっている
・バージョンの違い
・属性の初期設定に問題がある
・メソッドの入力に問題がある


 AttributeErrorって何?

「AttributeError: module ‘xxx’ has no attribute ‘yyy’」を直訳すると、「属性エラー:モジュール‘xxx’ に属性‘yyy’はありません」。すなわち、存在しないメソッド(クラス内に持つ関数)を実行しようとしていることになります。

同じような意味を持つエラーで「 'xxx' object has no attribute 'yyy'」もあります。


属性のスペルミス・誤字


 ただの誤字なんて初歩的じゃん…と侮れないのが恐ろしいところ。実際、質問サイトにある AttributeErrorの原因の1割は、このスペルミスです。特に初心者がやりがちなミスです。エラーが出たらまずはこれを疑いましょう。

以下のような簡単なコードでも、簡単にエラーが発生します。
 import random
 attack=random.randnt(1,7)#正しくはrandint

#module 'random' has no attribute 'ranint'

対処法として、まずはメソッド名があっているかどうか確認しましょう。もしくは、一度そのコードを書き直してみましょう。

コードを書き直してもエラーが続く場合、間違った名前で覚えている可能性があるので、モジュールのドキュメントを公式サイトやGithubで確認してみるのもいいでしょう。


ファイル名とモジュール名が同じになっている


カレントディレクトリにモジュール名と同じ名前のファイルが有ると、そのファイルが先に読み込まれてしまい、本来読み込むべきモジュールが読み込まれなくなります。

モジュールに関するメソッド全般が使えないとき、この原因を考えるといいでしょう。

対処法としては、ファイル名を変えるかファイル自体削除することです。モジュールを使ってプログラミングの練習をしている場合、モジュール名をそのままファイル名にしてしまいがちなので注意しましょう。


バージョンの違い


tensorflow・chainerなど発展途上のライブラリでは、バージョンによってメソッド名が変わっている(消えている)ことがあります。古いバージョンを使っている場合だけでなく、新しいバージョンを使っている場合でも起こる可能性はあります。

ほとんどのメソッドは使える、一部のメソッドだけ使えない場合に、この原因を想定するといいでしょう。

対処法としては、バージョンに合ったドキュメントを見て、目的のメソッドが存在するかどうか確認すること。存在しない場合、バージョンのずれがありえます。

バージョンにずれがあれば、一度モジュールをアンインストールしてから、以下のようにバージョンを指定してインストールしましょう。

pip install module==1.8.0 #moduleはモジュール名
 
モジュールのバージョンだけでなく、pythonのバージョン違いでも同様の問題が発生します。python2を使っていた人の場合、python3では扱いの異なる部分がいくつかあるので(特に文字列関連)注意しましょう。

参考記事:Python 2.7.x と 3.x の決定的な違いを例とともに(Postd)


属性の初期設定に問題がある
(自分でクラス・メソッドを作っている場合)

以下のコードのように、selfをつけ忘れて変数定義したり、インデントミスにより本来クラスの中に入るべきメソッド(関数)が独立してしまっていると、変数やメソッドを呼び出した際にエラーが発生します。
class hero():
    def __init__(self):
        HP=30 #selfがついていない
        
def attack(self): #インデントミスでclass内に入ってない
    print('attack!')

hoge=hero()
print(hoge.HP) #AttributeErrorが出る
hoge.attack()  #これもAttributeError

こうしたエラーは、自分でクラスやメソッドを作っている場合に起こり得るものです。

クラスの中にクラスを作るなど複雑な設計を行っている場合、インデントミスによるエラーの確率はさらに高くなります。できるだけシンプルな設計を心がけましょう。


メソッドの入力に問題がある

変数のオブジェクトが想定と異なる場合、AttributeError発生の原因となります。

大抵の場合、エラー箇所のコードに問題があるのではなく、それ以前の処理に問題があります。

例えば以下のようなコードだと、lst.append(1)によりリスト内の値がint型になっているため、本来str型に使うべきcapitalizeメソッドと噛み合わずエラーが発生します。

lst=[]
lst.append(1)#問題の原因はここ
print(lst[0].capitalize()) #AttributeError

変数について、想定している型と実際の型が同じかどうか注意しましょう。


別の例で、以下のコードのように関数の戻り値を定義していない場合、自動的に戻り値がNone(NoneType型)となり、これまたエラーの原因となります。
def hoge():
    moji='文字'
  #戻り値(return)が無い moji='a'#str型のように見えるけど… print(hoge().capitalize()) #やはりAttributeError

事前に値を設定しておいても、関数の戻り値によって値が上書きされてしまうためエラーになります。

今回の例ならバグを見つけるのは容易ですが、他からインストールしたモジュールを使った複雑なプログラムの場合、エラーの原因を見つけるのは難しくなります。

不正な値やタイムアウトによってNoneを返すことは大いに有り得る(スクレイピング系とか)ので、'NoneType' object has no attribute 'xxx'を見つけたら直前の処理を疑うと良いでしょう。  


まとめ

AttributeErrorになりうる基本的な原因について5つ紹介しました。

AttributeErrorに限らず、エラーメッセージはエラーの原因を突き止める上でとても重要です。

エラーメッセージを理解し、考えうるエラーの原因を経験や書籍を通じて蓄積することが、よりよいプログラミングにつながるでしょう。
このエントリーをはてなブックマークに追加

コメント

コメントフォーム
評価する
  • 1
  • 2
  • 3
  • 4
  • 5
  • リセット
  • 1
  • 2
  • 3
  • 4
  • 5
  • リセット