61

For the error:

TypeError: takes exactly 1 argument (2 given)

With the following class method:

def extractAll(tag):
   ...

and calling it:

e.extractAll("th")

The error seems very odd when I'm giving it 1 argument, the method should take only 1 argument, but it's saying I'm not giving it 1 argument....I know the problem can be fixed by adding self into the method prototype but I wanted to know the reasoning behind the error.

Am I getting it because the act of calling it via e.extractAll("th") also passes in self as an argument? And if so, by removing the self in the call, would I be making it some kind of class method that can be called like Extractor.extractAll("th")?

funk-shun
  • 4,331
  • 11
  • 32
  • 41

6 Answers6

82

The call

e.extractAll("th")

for a regular method extractAll() is indeed equivalent to

Extractor.extractAll(e, "th")

These two calls are treated the same in all regards, including the error messages you get.

If you don't need to pass the instance to a method, you can use a staticmethod:

@staticmethod
def extractAll(tag):
    ...

which can be called as e.extractAll("th"). But I wonder why this is a method on a class at all if you don't need to access any instance.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • it's reasonable to have this method in a class if i need to access the class's fields right?... – funk-shun Feb 07 '11 at 22:20
  • @funk-shun: Right, but than you would need a `classsmethod`, not a `staticmethod`. And often, I would just use an ordinary method for this kind of method. – Sven Marnach Feb 07 '11 at 22:39
  • 1
    @user2533809: Usually, the first parameter of a `classmethod` is called `cls`, because it's the class itself, not an instance of it. – Sven Marnach Jun 11 '14 at 15:26
  • 1
    thanks Sven Marnach for the info, so: `def extractAll(self, tag)` is called as: `my_obj.extractAll(tag)` | `@classmethod` `def extractAll(cls, tag)` is called as: `Extract.extractAll(tag)` – dajon Jun 11 '14 at 19:17
28

If a non-static method is member of a class, you have to define it like that:

def Method(self, atributes..)

So, I suppose your 'e' is instance of some class with implemented method that tries to execute and has too much arguments.

joaquin
  • 82,968
  • 29
  • 138
  • 152
Martin
  • 281
  • 3
  • 2
9

Am I getting it because the act of calling it via e.extractAll("th") also passes in self as an argument?

Yes, that's precisely it. If you like, the first parameter is the object name, e that you are calling it with.

And if so, by removing the self in the call, would I be making it some kind of class method that can be called like Extractor.extractAll("th")?

Not quite. A classmethod needs the @classmethod decorator, and that accepts the class as the first paramater (usually referenced as cls). The only sort of method that is given no automatic parameter at all is known as a staticmethod, and that again needs a decorator (unsurprisingly, it's @staticmethod). A classmethod is used when it's an operation that needs to refer to the class itself: perhaps instantiating objects of the class; a staticmethod is used when the code belongs in the class logically, but requires no access to class or instance.

But yes, both staticmethods and classmethods can be called by referencing the classname as you describe: Extractor.extractAll("th").

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • 1
    Both are also relatively rare in common, well written python code. If you think you need to use them right away, I suggest you reconsider whether it needs to be inside a class at all. Perhaps you're trying to write Java with python. – chmullig Feb 05 '11 at 22:02
  • 1
    I kind of like using classmethod as factory methods: it makes it explicit what type of object(s) are being created. – Matthew Schinckel Feb 06 '11 at 08:46
4

Summary (Some examples of how to define methods in classes in python)

#!/usr/bin/env python   # (if running from bash)

class Class1(object):

    def A(self, arg1):
        print arg1
        # this method requires an instance of Class1   
        # can access self.variable_name, and other methods in Class1

    @classmethod
    def B(cls, arg1):
        cls.C(arg1)
        # can access methods B and C in Class1 

    @staticmethod
    def C(arg1):
        print arg1
        # can access methods B and C in Class1 
        # (i.e. via Class1.B(...) and Class1.C(...))

Example

my_obj=Class1()

my_obj.A("1")
# Class1.A("2") # TypeError: method A() must be called with Class1 instance

my_obj.B("3")
Class1.B("4")
my_obj.C("5")
Class1.C("6")`
dajon
  • 2,350
  • 1
  • 16
  • 17
4

Yes, when you invoke e.extractAll(foo), Python munges that into extractAll(e, foo).

From http://docs.python.org/tutorial/classes.html

the special thing about methods is that the object is passed as the first argument of the function. In our example, the call x.f() is exactly equivalent to MyClass.f(x). In general, calling a method with a list of n arguments is equivalent to calling the corresponding function with an argument list that is created by inserting the method’s object before the first argument.

Emphasis added.

payne
  • 13,833
  • 5
  • 42
  • 49
1

try using:

def extractAll(self,tag):

attention to self

Rui Lima
  • 7,185
  • 4
  • 31
  • 42