494

If I have a class ...

class MyClass:

    def method(arg):
        print(arg)

... which I use to create an object ...

my_object = MyClass()

... on which I call method("foo") like so ...

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

... why does Python tell me I gave it two arguments, when I only gave one?

wjandrea
  • 28,235
  • 9
  • 60
  • 81
Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160
  • 34
    That message has umpteen causes; the specific reason here is that all instance methods expect a first arg which by custom we call `self`. So declaring `def method(arg):` is wrong for a method, it should be `def method(self, arg):`. When the method dispatch tries to call `method(arg):` and match up two parameters `self, arg` against it, you get that error. – smci May 02 '20 at 14:56

11 Answers11

612

In Python, this:

my_object.method("foo")

... is syntactic sugar, which the interpreter translates behind the scenes into:

MyClass.method(my_object, "foo")

... which, as you can see, does indeed have two arguments - it's just that the first one is implicit, from the point of view of the caller.

This is because most methods do some work with the object they're called on, so there needs to be some way for that object to be referred to inside the method. By convention, this first argument is called self inside the method definition:

class MyNewClass:

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

If you call method("foo") on an instance of MyNewClass, it works as expected:

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

Occasionally (but not often), you really don't care about the object that your method is bound to, and in that circumstance, you can decorate the method with the builtin staticmethod() function to say so:

class MyOtherClass:

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

... in which case you don't need to add a self argument to the method definition, and it still works:

>>> my_other_object = MyOtherClass()
>>> my_other_object.method("foo")
foo
Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160
  • 184
    In short: Adding `self` as first argument to the method solves the problem. – amoebe Jun 10 '17 at 11:15
  • 5
    or just adding @staticmethod before defining it. Cool – Ujjwal Sep 06 '20 at 06:38
  • Can you elaborate a bit on this bit here: "Occasionally (but not often), you really don't care about the object that your method is bound to..." I come from a Java and .NET background, and I frequently organize methods into appropriate classes for grouping/organization. Would that not be valid here in Python as well? – joeschmoe54321 Jun 20 '23 at 19:35
  • @joeschmoe54321 in Python you'd typically use modules and packages to group functions, not classes. – Zero Piraeus Jun 22 '23 at 14:58
43

In simple words

In Python you should add self as the first parameter to all defined methods in classes:

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

Then you can use your method according to your intuition:

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

For a better understanding, you can also read the answers to this question: What is the purpose of self?

wjandrea
  • 28,235
  • 9
  • 60
  • 81
simhumileco
  • 31,877
  • 16
  • 137
  • 115
  • 4
    What's wrong with this answer? Why did someone give her a negative point? After all, it is the answer to the question and is distinguished by its simplicity compared to other answers, which may be important for some people who are looking for an answer. Isn't it? – simhumileco Aug 08 '19 at 21:53
  • 3
    It's wrong to say that you should add `self` argument to _ALL_ defined methods in classes. In the example above there is no use for `self` inside the method, therefore it can be decorated with `@staticmethod` which in turn wouldn't require you to create an instance of the class. You can read more about it here: https://docs.python.org/3/library/functions.html?highlight=staticmethod#staticmethod – grafuls May 27 '22 at 12:30
  • 2
    It's also possible to have [`@classmethod`s](https://docs.python.org/3/library/functions.html#classmethod), which take `cls` as their first parameter, not `self`. – wjandrea Nov 15 '22 at 18:16
25

Something else to consider when this type of error is encountered:

I was running into this error message and found this post helpful. Turns out in my case I had overridden an __init__() where there was object inheritance.

The inherited example is rather long, so I'll skip to a more simple example that doesn't use inheritance:

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")

Result is:

<__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 didn't catch this typo. Nor did Notepad++ (other editors/IDE's might).

Granted, this is a "takes no parameters" TypeError, it isn't much different than "got two" when expecting one, in terms of object initialization in Python.

Addressing the topic: An overloading initializer will be used if syntactically correct, but if not it will be ignored and the built-in used instead. The object won't expect/handle this and the error is thrown.

In the case of the sytax error: The fix is simple, just edit the custom init statement:

def __init__(self, name):
    self.name = name
simhumileco
  • 31,877
  • 16
  • 137
  • 115
Jonru
  • 374
  • 3
  • 6
  • 3
    There's no `SyntaxError` here. The code is syntactically correct; it just correctly defines a method named `___init__`, which nobody is ever going to call, instead of the special method `__init__`. That's why no error is detected—because there isn't one to detect. – abarnert Jun 27 '18 at 21:29
  • Exact same thing happened to me, but with `__int__(self, ...):`. Hours wasted because of that typo. – anonymous Sep 05 '22 at 20:02
  • I'm happy you found a solution, but this is a totally different issue than the one in the question. I would say you could [post your own question](/help/self-answer), but the same sort of thing has already been posted, for example: ["This constructor takes no arguments" error in `__init__`](/q/12448414/4518341) (typo was `_init_`). – wjandrea Nov 15 '22 at 18:36
21

This issue can also be caused by failing to pass keyword arguments to a function properly.

For example, given a method defined like:

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

a call like this:

self.create_properties_frame(frame, kw_gsp)

will cause TypeError: create_properties_frame() takes 2 positional arguments but 3 were given, because the kw_gsp dictionary is treated as a positional argument instead of being unpacked into separate keyword arguments.

The solution is to add ** to the argument:

self.create_properties_frame(frame, **kw_gsp)
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Stanislav Pankevich
  • 11,044
  • 8
  • 69
  • 129
  • 1
    Coming from JavaScript, I expect to be able to pass a list or dictionary as an argument. But it seems like that's not how Python works: you have to destructure the list with * or **, the latter being for a keyworded argument list. – Little Brain Aug 23 '19 at 10:17
  • 3
    @LittleBrain: yes you can pass a list (or dict) if you want them to be treated as a list (/dict) inside the function. But if you want their individual values unpacked and matched against args (/kwargs) in the function, then you need the `*args` (/`**kwargs`) syntax. – smci May 02 '20 at 14:21
15

As mentioned in other answers - when you use an instance method you need to pass self as the first argument - this is the source of the error.

With addition to that,it is important to understand that only instance methods take self as the first argument in order to refer to the instance.

In case the method is Static you don't pass self, but a cls argument instead (or class_).

Please see an example below.

class City:

   country = "USA" # This is a class level attribute which will be shared across all instances  (and not created PER instance)

   def __init__(self, name, location, population):
       self.name       = name
       self.location   = location
       self.population = population
 
   # This is an instance method which takes self as the first argument to refer to the instance 
   def print_population(self, some_nice_sentence_prefix):
       print(some_nice_sentence_prefix +" In " +self.name + " lives " +self.population + " people!")

   # This is a static (class) method which is marked with the @classmethod attribute
   # All class methods must take a class argument as first param. The convention is to name is "cls" but class_ is also ok
   @classmethod
   def change_country(cls, new_country):
       cls.country = new_country

Some tests just to make things more clear:

# Populate objects
city1 = City("New York",    "East", "18,804,000")
city2 = City("Los Angeles", "West", "10,118,800")

#1) Use the instance method: No need to pass "self" - it is passed as the city1 instance
city1.print_population("Did You Know?") # Prints: Did You Know? In New York lives 18,804,000 people!

#2.A) Use the static method in the object
city2.change_country("Canada")

#2.B) Will be reflected in all objects
print("city1.country=",city1.country) # Prints Canada
print("city2.country=",city2.country) # Prints Canada
Rot-man
  • 18,045
  • 12
  • 118
  • 124
  • 1
    This terminology is wrong. [`classmethod`s](https://docs.python.org/3/library/functions.html#classmethod) and [`staticmethod`s](https://docs.python.org/3/library/functions.html#staticmethod) are two different things. `classmethod`s take `cls` while `staticmethod`s don't have any required parameters. – wjandrea Nov 15 '22 at 18:25
  • Also, I don't think this is a good example of a `classmethod`, because why would you want one `City` instance to affect all others? Like, why does the `City` class even have a `country` attribute in the first place? Shouldn't each `City` instance define its own country? Say I wanted to make a `City` instance for Tokyo and another for Toronto; that's not possible with this, so how is it useful? [Here's a better example](/a/12179752/4518341), including a `staticmethod`. – wjandrea Nov 15 '22 at 18:28
  • Thanks @wjandrea, I'm not 100% sure I understood your comments and why my answer is giving a wrong information in any way. – Rot-man Nov 15 '22 at 19:35
9

It occurs when you don't specify the no of parameters the __init__() or any other method looking for.

For example:

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")

When you run the above programme, it gives you an error like that:

TypeError: __init__() takes 1 positional argument but 6 were given

How we can get rid of this thing?

Just pass the parameters, what __init__() method looking for

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))
wjandrea
  • 28,235
  • 9
  • 60
  • 81
Trinadh Koya
  • 1,089
  • 15
  • 19
6

If you want to call method without creating object, you can change method to static method.

class MyClass:

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

MyClass.method("i am a static method")
Manikandan Raju
  • 117
  • 3
  • 3
5

I get this error when I'm sleep-deprived, and create a class using def instead of class:

def MyClass():
    def __init__(self, x):
        self.x = x

a = MyClass(3)
-> TypeError: MyClass() takes 0 positional arguments but 1 was given
wjandrea
  • 28,235
  • 9
  • 60
  • 81
Simon Alford
  • 2,405
  • 1
  • 12
  • 10
  • I'm happy you found a solution, but this is a totally different issue than the one in the question. I would say you could [post your own question](/help/self-answer), but the same thing has already been posted: [TypeError: `__init__` takes 1 positional argument but 2 were given](/q/73328296/4518341). – wjandrea Nov 15 '22 at 18:41
  • @wjandrea, this answer is for the exact error message of the subject. I don't know about you, but I don't read questions, I read the subject and answers. – run_the_race Jan 27 '23 at 20:14
  • @run_the_race Yeah, it's best to read the whole question, but I do skip it myself sometimes. So, I've updated the title to better reflect the problem. – wjandrea Jan 27 '23 at 20:43
0

If you experience this with Django then this is what it implies:

  1. add an object to the function, Django will understand the rest, example
def display_genre(self, obj):
        return ', '.join(genre.name for genre in obj.genre.all())}

King Chudi
  • 61
  • 2
-1

You should actually create a class:

class accum:
    def __init__(self):
        self.acc = 0
    def accumulator(self, var2add, end):
        if not end:
            self.acc+=var2add
        return self.acc
Coddy
  • 549
  • 4
  • 18
-1

In my case, I forgot to add the ()

I was calling the method like this

obj = className.myMethod

But it should be is like this

obj = className.myMethod()
Gabriel Arghire
  • 1,992
  • 1
  • 21
  • 34