TypeError: method () принимает 1 позиционный аргумент, но 2


271

Если у меня есть класс ...

class MyClass:

    def method(arg):
        print(arg)

... который я использую для создания объекта ...

my_object = MyClass()

... на котором я так называю method("foo")...

>>> my_object.method("foo")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method() takes exactly 1 positional argument (2 given)

... почему Python говорит мне, что я дал ему два аргумента, когда я дал только один?


Это сообщение имеет множество причин; конкретная причина здесь в том, что все методы экземпляра ожидают первый аргумент, который мы обычно вызываем self. Таким образом, объявление def method(arg):неверно для метода, оно должно быть def method(self, arg):. Когда диспетчер метода пытается вызвать method(arg):и сопоставить два параметра self, argс ним, вы получаете эту ошибку.
SMCI

Ответы:


368

В Python это:

my_object.method("foo")

... это синтаксический сахар , который переводчик за кадром переводит на:

MyClass.method(my_object, "foo")

... который, как вы можете видеть, действительно имеет два аргумента - просто первый неявный, с точки зрения вызывающего.

Это связано с тем, что большинство методов выполняют некоторую работу с объектом, к которому они обращаются, поэтому должен быть какой-то способ для ссылки на этот объект внутри метода. По соглашению этот первый аргумент вызывается selfвнутри определения метода:

class MyNewClass:

    def method(self, arg):
        print(self)
        print(arg)

Если вы вызываете method("foo")экземпляр MyNewClass, он работает как положено:

>>> my_new_object = MyNewClass()
>>> my_new_object.method("foo")
<__main__.MyNewClass object at 0x29045d0>
foo

Иногда (но не часто) вы действительно не заботитесь об объекте, с которым связан ваш метод, и в этом случае вы можете украсить метод встроенной staticmethod()функцией, чтобы сказать так:

class MyOtherClass:

    @staticmethod
    def method(arg):
        print(arg)

... в этом случае вам не нужно добавлять selfаргумент в определение метода, и он все еще работает:

>>> my_other_object = MyOtherClass()
>>> my_other_object.method("foo")
foo

99
Вкратце: добавление в selfкачестве первого аргумента метода решает проблему.
amoebe

@amoebe - мой тип человека
Карлос

21

Что-то еще, чтобы рассмотреть, когда встречается этот тип ошибки:

Я столкнулся с этим сообщением об ошибке и нашел этот пост полезным. Оказывается, в моем случае я переопределил, __init__()где было наследование объекта.

Унаследованный пример довольно длинный, поэтому я перейду к более простому примеру, который не использует наследование:

class MyBadInitClass:
    def ___init__(self, name):
        self.name = name

    def name_foo(self, arg):
        print(self)
        print(arg)
        print("My name is", self.name)


class MyNewClass:
    def new_foo(self, arg):
        print(self)
        print(arg)


my_new_object = MyNewClass()
my_new_object.new_foo("NewFoo")
my_bad_init_object = MyBadInitClass(name="Test Name")
my_bad_init_object.name_foo("name foo")

Результат:

<__main__.MyNewClass object at 0x033C48D0>
NewFoo
Traceback (most recent call last):
  File "C:/Users/Orange/PycharmProjects/Chapter9/bad_init_example.py", line 41, in <module>
    my_bad_init_object = MyBadInitClass(name="Test Name")
TypeError: object() takes no parameters

PyCharm не уловил эту опечатку. Также не Notepad ++ (другие редакторы / IDE могут).

Конечно, это TypeError типа «не принимает параметры», он мало чем отличается от «получил два» при ожидании единицы с точки зрения инициализации объекта в Python.

Обращаясь к теме: Инициализатор перегрузки будет использоваться, если синтаксически правильный, но если нет, он будет игнорироваться и вместо него будет использоваться встроенный. Объект не будет ожидать / обрабатывать это, и выдается ошибка.

В случае синтаксической ошибки: исправить это просто, просто отредактируйте пользовательский оператор init:

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

1
Там нет SyntaxErrorздесь. Код синтаксически правильный; он просто правильно определяет метод с именем ___init__, который никто не собирается вызывать, вместо специального метода __init__. Вот почему ошибка не обнаружена, потому что ее нет.
abarnert

14

Простыми словами.

В Python вы должны добавить selfаргумент в качестве первого аргумента для всех определенных методов в классах:

class MyClass:
  def method(self, arg):
    print(arg)

Тогда вы можете использовать свой метод в соответствии с вашей интуицией:

>>> my_object = MyClass()
>>> my_object.method("foo")
foo

Это должно решить вашу проблему :)

Для лучшего понимания вы также можете прочитать ответы на этот вопрос: какова цель самого себя?


2
Что не так с этим ответом? Почему кто-то дал ей отрицательный балл? В конце концов, это ответ на вопрос и отличается своей простотой по сравнению с другими ответами, что может быть важно для некоторых людей, которые ищут ответ. Не так ли?
simhumileco

10

Новичок в Python, у меня была эта проблема, когда я **неправильно использовал функцию Python . Попытка вызвать это определение откуда-то:

def create_properties_frame(self, parent, **kwargs):

использование вызова без двойной звезды вызывало проблему:

self.create_properties_frame(frame, kw_gsp)

TypeError: create_properties_frame () принимает 2 позиционных аргумента, но 3 были заданы

Решение состоит в том, чтобы добавить **к аргументу:

self.create_properties_frame(frame, **kw_gsp)

1
Исходя из JavaScript, я ожидаю, что смогу передать список или словарь в качестве аргумента. Но похоже, что Python работает не так: вы должны деструктурировать список с помощью * или **, последний - для списка аргументов с ключевыми словами.
Литтл Мозг

1
@LittleBrain: да, вы можете передать список (или dict), если хотите, чтобы они рассматривались как список (/ dict) внутри функции. Но если вы хотите, чтобы их отдельные значения были распакованы и сопоставлены с аргументами (/ kwargs) в функции, то вам нужен синтаксис *args(/ **kwargs).
SMCI

9

Это происходит, когда вы не указываете ни одно из параметров, которое __init__()ищет какой-либо другой метод.

Например:

class Dog:
    def __init__(self):
        print("IN INIT METHOD")

    def __unicode__(self,):
        print("IN UNICODE METHOD")

    def __str__(self):
        print("IN STR METHOD")

obj=Dog("JIMMY",1,2,3,"WOOF")

Когда вы запускаете вышеуказанную программу, она выдает такую ​​ошибку:

Ошибка типа: __init __ () принимает 1 позиционный аргумент, но 6 были заданы

Как мы можем избавиться от этой вещи?

Просто передайте параметры, какой __init__()метод ищете

class Dog:
    def __init__(self, dogname, dob_d, dob_m, dob_y, dogSpeakText):
        self.name_of_dog = dogname
        self.date_of_birth = dob_d
        self.month_of_birth = dob_m
        self.year_of_birth = dob_y
        self.sound_it_make = dogSpeakText

    def __unicode__(self, ):
        print("IN UNICODE METHOD")

    def __str__(self):
        print("IN STR METHOD")


obj = Dog("JIMMY", 1, 2, 3, "WOOF")
print(id(obj))

1

Вы должны создать класс:

class accum:
    def __init__(self):
        self.acc = 0
    def accumulator(self, var2add, end):
        if not end:
            self.acc+=var2add
    return self.acc


-1

Передайте clsпараметр в, @classmethodчтобы решить эту проблему.

@classmethod
def test(cls):
    return ''
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.