Pythonの「NameError: name 'self' is not defined」エラーの原因と解決策
Pythonのクラス内で「NameError: name 'self' is not defined」というエラーに遭遇したことはありませんか?このエラーは、「self」がメソッドの引数として正しく指定されていない場合や、メソッドの引数リスト内で「self」を参照しようとした場合に発生します。
この記事では、このエラーの意味と発生理由を詳しく解説し、実際のコード例を通して解決方法をわかりやすく説明します。
NameError: name 'self' is not defined とは
「self」変数は、クラス内のオブジェクトに関する情報を保持する特別な変数です。オブジェクトに割り当てられたすべての値は、「self」変数を通じてアクセスできます。
メソッド内で「self」を使用したい場合は、必ず引数として渡す必要があります。「self」はメソッド内部からのみアクセス可能なため、メソッドの他の引数の中で使用することはできません。
以下の場合に「NameError: name 'self' is not defined」エラーが発生します:
- メソッドの引数に「self」を指定し忘れている
- 別の引数のデフォルト値として「self」を使用している
それでは、それぞれのケースを順番に見ていきましょう。
シナリオ1:「self」が引数として指定されていない
メソッド内で「self」にアクセスするには、必ず引数リストに「self」を含める必要があります。「self」はグローバル変数ではなく、クラス内のローカルな変数だからです。
映画の情報を管理するクラスを持つプログラムを書いてみましょう。まず、映画に関する値を保持するコンストラクタでクラスを定義します:
class Movie:
def __init__(self, name, year_released):
self.name = name
self.year_released = year_released
このクラスは、映画のタイトル(name)と公開年(year_released)の2つの値を保持できます。次に、「year_released」の値を変更できるメソッドを宣言します:
def change_year(year_released):
self.year_released = year_released
print("{} was released in {}.".format(self.name, self.year_released))
コードをテストするために、クラスのオブジェクトを作成します。このオブジェクトは1996年に公開された映画『Happy Gilmore』を表しています:
happy_gilmore = Movie("Happy Gilmore")
happy_gilmore.change_year(1996)
オブジェクトに対してchange_year()メソッドを呼び出し、映画の公開年を1996年に設定しました。コードを実行してみましょう:
Traceback (most recent call last):
File "main.py", line 11, in <module>
happy_gilmore.change_year()
File "main.py", line 7, in change_year
self.year_released = year_released
NameError: name 'self' is not defined
エラーが発生しました。これは、メソッドに「self」を引数として渡していないことが原因です。change_year()メソッドの最初の引数として「self」を追加することで、このエラーを修正できます:
def change_year(self, year_released):
self.year_released = year_released
print("{} was released in {}.".format(self.name, self.year_released))
もう一度コードを実行します:
Happy Gilmore was released in 1996.
今度は正常に実行されました!
シナリオ2:別の引数のデフォルト値として「self」を使用している
「self」は関数が呼び出されたときに評価されます。そのため、関数の引数リスト内で「self」を参照する引数を指定することはできません。
先ほどの「year_released」メソッドを更新して、公開年の変更が指定されなかった場合に、映画の公開年が変更されていないことを知らせるメッセージをコンソールに出力するようにしましょう。
これを実現するには、デフォルト引数を設定します:
def change_year(self, year_released=self.year_released):
if year_released != self.year_released:
self.year_released = year_released
print("{} was released in {}.".format(self.name, self.year_released))
else:
print("This movie has not been changed.")
print(year_released)
ここで「year_released」には「self.year_released」がデフォルト値として設定されています。つまり、変更後の年を指定しなければデフォルト値が使われ、指定すればその値が優先されます。
指定した値が「self.year_released」と異なる場合は公開年が更新され、同じ場合は「映画は変更されていない」というメッセージがコンソールに出力されます。if文の評価後、「year_released」の値がコンソールに出力されます。
コードを実行してみましょう:
Traceback (most recent call last):
File "main.py", line 1, in <module>
class Movie:
File "main.py", line 6, in Movie
def change_year(self, year_released=self.year_released):
NameError: name 'self' is not defined
再びエラーが発生しました。これは、引数リスト内の別の引数で「self」を使おうとしたためです。
このエラーを修正するには、引数リスト内ではなく、関数内部で「year_released」に「self.year_released」の値を設定するようにします:
def change_year(self, year_released=None):
if year_released != self.year_released:
self.year_released = year_released
print("{} was released in {}.".format(self.name, self.year_released))
else:
year_released = self.year_released
print("This movie has not been changed.")
print(year_released)
このコードでは、関数呼び出し時に「year_released」の値が指定されなかった場合、関数内で「year_released」を「self.year_released」と等しく設定しています。
新しいMovieオブジェクトを作成して、コードをテストしてみましょう:
happy_gilmore = Movie("Happy Gilmore", 1995)
happy_gilmore.change_year(1996)
『Happy Gilmore』の公開年を誤って1995年と入力してしまいました。change_year()メソッドを使って修正する必要があります。コードの実行結果は以下の通りです:
Happy Gilmore was released in 1996.
1996
コードは正常に実行されました。次に、「year_released」の値がすでにchange_year()メソッドで指定した値と一致している場合の動作も確認してみましょう:
happy_gilmore = Movie("Happy Gilmore", 1996)
happy_gilmore.change_year(1996)
実行結果:
This movie has not been changed.
1996
この場合、コードはelse文を実行し、映画が変更されていないことを教えてくれます。
まとめ
「NameError: name 'self' is not defined」エラーは、メソッドの位置引数として「self」を指定し忘れた場合や、引数リスト内の別の引数で「self」を使用した場合に発生します。
このエラーを解決するには、クラス内のすべてのメソッドで「self」を使用している場合、必ず引数リストに「self」を含めるようにしてください。それでも解決しない場合は、引数のデフォルト値が「self」に依存していないか確認しましょう。
これで、プロの開発者のようにこのPythonエラーを解決できるようになりました!
-
Pythonの継承とは?単一継承と階層継承の基本をサンプルコードで解説
本記事では、Python 3.xにおける継承(インヘリタンス)とクラスの拡張方法について詳しく解説します。 継承とは、現実世界のモノや概念の関係性を自然に表現できる、オブジェクト指向プログラミングの中核となる仕組みです。継承を活用すると、次のようなメリットが得られます。 再利用性:すでに書いたコードを流用でき、重複を削減できる 推移性:クラス間の関係を連鎖的に引き継げる 開発速度の向上:ゼロから書かずに済むため、短期間で開発できる 保守性・拡張性:既存クラスを壊さずに機能を追加しやすい 継承の5つの種類 Pythonの継承は、その構造によって主に以下の5種類に分類されます。 単一継承(
-
PythonでNameError例外をキャッチする方法をわかりやすく解説
NameErrorは、コード内で現在のスコープに存在しない名前(変数や関数など)を参照したときに発生する例外です。典型的な例としては、定義していない変数名をそのまま使ってしまうケースが挙げられます。 以下のコードでは、try-except文を使ってNameErrorを捕捉し、エラーメッセージと例外の種類を確認しています。 サンプルコード import sys try: def foo(): print(magnolia) foo() except NameError as e: print(e) print(type(e).__name__)