「TypeError: func() takes X positional arguments but Y were given」の原因と対処法|Pythonのエラーを解決

Pythonで関数やメソッドを実行していると、
TypeError: func() takes X positional arguments but Y were given
というエラーが表示されることがあります。
このエラーは、関数が受け取れる引数の数と、実際に渡した引数の数が一致していない場合に発生します。
本記事では、「func() takes X positional arguments but Y were given」の意味から、具体的な原因、解決方法、クラスのメソッドで発生するケースまで、初心者にもわかりやすく解説します。
「func() takes X positional arguments but Y were given」とは?
「func() takes X positional arguments but Y were given」は、PythonのTypeErrorの一種です。
エラーメッセージを分解すると、次の意味になります。
func() takes X positional arguments but Y were given
-
func():呼び出した関数名 -
takes X positional arguments:関数はX個の位置引数を受け取る -
but Y were given:しかしY個の引数が渡された
つまり、
関数が想定している引数の数と、実際に渡した引数の数が違います
という意味です。
基本的な例
例えば、1つの引数を受け取る関数を定義します。
def greet(name):
print(f"こんにちは、{name}さん")
この関数には、nameという引数が1つあります。
正常な呼び出しは次のとおりです。
greet("田中")
ところが、2つの引数を渡すとエラーになります。
greet("田中", "太郎")
実行すると、環境やPythonのバージョンによって表現は多少異なりますが、次のようなエラーになります。
TypeError: greet() takes 1 positional argument but 2 were given
これは、
greet()は1個の引数を受け取る設定なのに、2個渡されています
という意味です。
XとYは何を意味している?
エラーの数字を見ることで、原因を判断できます。
例えば、
TypeError: func() takes 2 positional arguments but 3 were given
なら、
takes 2
は「2個まで受け取れる」という意味で、
3 were given
は「3個渡した」という意味です。
つまり、
定義:2個
↓
実際:3個
↓
1個多い
という状態です。
逆に、
TypeError: func() takes 3 positional arguments but 2 were given
なら、関数が3個の引数を必要としているのに、2個しか渡していません。
原因1:関数に渡す引数が多すぎる
最も基本的な原因です。
def add(a, b):
return a + b
この関数は2つの引数を受け取ります。
add(10, 20)
これは正常です。
しかし、
add(10, 20, 30)
とすると、
TypeError: add() takes 2 positional arguments but 3 were given
となります。
対処方法
関数の定義を確認して、必要な数だけ引数を渡します。
add(10, 20)
もし3つの値を受け取りたいのであれば、関数側を変更します。
def add(a, b, c):
return a + b + c
原因2:引数を渡すのを忘れている
反対に、引数が足りない場合にも似たエラーが発生します。
例えば、
def greet(name):
print(name)
に対して、
greet()
とすると、
TypeError: greet() missing 1 required positional argument: 'name'
となります。
「takes X positional arguments but Y were given」と完全に同じエラーではありませんが、原因は同じく引数の数が合っていないことです。
原因3:クラスのメソッドでselfを忘れている
「func() takes X positional arguments but Y were given」で特に注意したいのが、クラスのメソッドです。
例えば、次のコードを見てください。
class Person:
def greet(name):
print(f"こんにちは、{name}さん")
一見すると問題なさそうに見えます。
しかし、
person = Person()
person.greet("田中")
とすると、エラーになることがあります。
TypeError: Person.greet() takes 1 positional argument but 2 were given
なぜでしょうか?
Pythonではメソッド呼び出し時にselfが渡される
クラスのインスタンスメソッドでは、通常、最初の引数にselfを指定します。
正しくは、
class Person:
def greet(self, name):
print(f"こんにちは、{name}さん")
とします。
そして、
person = Person()
person.greet("田中")
と呼び出します。
内部的には、おおよそ次のようなイメージです。
Person.greet(person, "田中")
つまり、selfが自動的に渡されています。
そのため、
def greet(name):
としてしまうと、nameにselfが入ってしまい、さらに"田中"が渡されることで引数が1つ多くなります。
selfを忘れた場合の解決方法
次のように修正します。
修正前
class Person:
def greet(name):
print(name)
修正後
class Person:
def greet(self, name):
print(name)
これで、
person = Person()
person.greet("田中")
が正常に動作します。
原因4:@staticmethodと通常のメソッドを混同している
クラスのメソッドでは、selfを使わない場合があります。
例えば、
class Calculator:
def add(a, b):
return a + b
このようなメソッドをインスタンスから呼び出すと、selfが自動的に渡されます。
そのため、意図的にインスタンスを使わないのであれば、@staticmethodを利用できます。
class Calculator:
@staticmethod
def add(a, b):
return a + b
これなら、
Calculator.add(10, 20)
と呼び出せます。
通常のメソッドとstaticmethodの違い
例えば通常のメソッドは、
class Calculator:
def add(self, a, b):
return a + b
です。
呼び出すときは、
calc = Calculator()
calc.add(10, 20)
とします。
一方、staticmethodなら、
class Calculator:
@staticmethod
def add(a, b):
return a + b
として、
Calculator.add(10, 20)
と呼び出せます。
インスタンス自身を使わない処理なら、staticmethodを検討するとよいでしょう。
原因5:関数の定義を変更したのに呼び出し側を変更していない
例えば、もともと次の関数だったとします。
def greet(name):
print(name)
呼び出し側は、
greet("田中")
です。
その後、関数を変更して、
def greet(name, age):
print(name, age)
とした場合、呼び出し側を、
greet("田中")
のままにすると引数が不足します。
逆に、関数の引数を減らしたのに、呼び出し側で以前の引数を渡し続けてもエラーになります。
そのため、
関数の定義と関数の呼び出し側をセットで確認することが重要です。
原因6:*argsを使っていない
関数に渡される引数の数が変わる可能性がある場合は、*argsを使う方法があります。
例えば、
def show(*args):
print(args)
とすると、複数の位置引数を受け取れます。
show(10)
show(10, 20)
show(10, 20, 30)
それぞれ実行できます。
argsにはタプルとして値が入ります。
def show(*args):
print(args)
show(10, 20, 30)
結果:
(10, 20, 30)
ただし、単純に引数の数が間違っているだけなら、*argsで解決するのではなく、関数の定義と呼び出し側を正しく修正することが基本です。
*argsと通常の引数の違い
通常の関数:
def greet(name):
print(name)
1つの引数を受け取ります。
一方、
def greet(*names):
print(names)
なら複数の引数を受け取れます。
greet("田中", "佐藤", "鈴木")
結果:
('田中', '佐藤', '鈴木')
**kwargsとの違い
キーワード引数を柔軟に受け取りたい場合は、**kwargsを使います。
def show(**kwargs):
print(kwargs)
例えば、
show(name="田中", age=30)
とすると、
{'name': '田中', 'age': 30}
のようになります。
整理すると、
| 書き方 | 受け取るもの |
|---|---|
*args |
複数の位置引数 |
**kwargs |
複数のキーワード引数 |
です。
エラーが発生したときの確認ポイント
「func() takes X positional arguments but Y were given」が発生したら、次の順番で確認すると効率的です。
1. 関数の定義を確認する
def func(a, b):
なら、基本的に2つの位置引数を受け取ります。
2. 呼び出し側を確認する
func(10, 20, 30)
となっていないか確認します。
3. selfを確認する
クラスのメソッドなら、
def func(self, value):
のようにselfが必要ではないか確認します。
4. @staticmethodが必要か確認する
インスタンス情報を利用しないメソッドなら、
@staticmethod
が適切な場合があります。
5. *argsの必要性を確認する
引数の数が可変になる設計なら、
def func(*args):
を検討します。
実際のエラーを確認する方法
例えば次のプログラムを実行します。
def calculate(a, b):
return a + b
result = calculate(10, 20, 30)
エラーは、
TypeError: calculate() takes 2 positional arguments but 3 were given
です。
この場合、
takes 2
なので、関数は2個の引数を受け取る設定です。
一方、
3 were given
なので、3個の引数を渡しています。
したがって、
calculate(10, 20)
に修正すれば解決します。
「positional arguments」とは?
エラーメッセージに出てくるpositional argumentsは、位置引数を意味します。
例えば、
def greet(name, age):
print(name, age)
に対して、
greet("田中", 30)
とすると、
"田中" → name
30 → age
というように、引数の位置によって対応するパラメータが決まります。
これが位置引数です。
キーワード引数ならどうなる?
Pythonでは、引数名を指定して値を渡すこともできます。
greet(name="田中", age=30)
これはキーワード引数です。
位置引数とは異なり、
name="田中"
age=30
のように、パラメータ名を明示します。
エラーを調べるときは、
-
positional arguments(位置引数)
-
keyword arguments(キーワード引数)
を区別すると原因を見つけやすくなります。
よくある間違い
間違い1:引数を1つ多く渡す
def func(a, b):
pass
func(1, 2, 3)
修正
func(1, 2)
間違い2:selfを忘れる
class Sample:
def func(value):
print(value)
修正
class Sample:
def func(self, value):
print(value)
間違い3:staticmethodを使うべき処理を通常のメソッドにする
class Sample:
def func(a, b):
return a + b
修正例
class Sample:
@staticmethod
def func(a, b):
return a + b
エラーを解決するための考え方
このエラーが出たときは、難しく考える必要はありません。
まず、
takes X positional arguments
と
Y were given
を比較します。
例えば、
takes 2 positional arguments but 3 were given
なら、
関数側:2個
呼び出し側:3個
です。
つまり、1個多いと判断できます。
一方、
takes 3 positional arguments but 2 were given
なら、
関数側:3個
呼び出し側:2個
なので、1個足りないと判断できます。
まとめ
「func() takes X positional arguments but Y were given」は、Pythonでよく遭遇するTypeErrorです。
主な原因は、関数が受け取る引数の数と、実際に渡している引数の数が一致していないことです。
特にクラスを利用している場合は、selfの付け忘れが原因になることがあります。
チェックするときは、次のポイントを確認しましょう。
-
関数定義の引数の数を確認する
-
関数呼び出し側の引数の数を確認する
-
selfの付け忘れがないか確認する -
@staticmethodが必要か確認する -
可変長引数なら
*argsを検討する
まずはエラーメッセージの
takes X positional arguments
と
Y were given
の数字を比較すると、原因をかなり絞り込めます。
Pythonの引数エラーは、関数の「定義」と「呼び出し」を見比べるのが解決への近道です。
他のPythonエラーの原因と対処法はPythonエラー一覧と対処法に種類別でまとめています。エラーメッセージの読み方もあわせて解説しています。


