1

I've just started learning about object orientated python and in the course I was taking, one of the first things done was to understand the error this code gives.

class NewList():
    def first_method():
        print("hello")

instance = NewList()
instance.first_method()

Here is the error.

---------------------------------------------------------------------
TypeError                           Traceback (most recent call last)
ipython-input-44-9e10ffed0a3f in module()
----> 1 instance.first_method()

TypeError: first_method() takes 0 positional arguments but 1 was given

My understanding is that when you call a method belonging to a particular object, python actually does this instead:

instance.first_method(instance)

But as we haven't given our method any positional arguments, there is an error.

I tried to experiment with this using other classes. I took the string class and tried the same thing.

instance_2=str()
result=instance_2.title()
print(result)

Here there was no error. My reasoning was that in the source code somewhere ( I tried to look and find out myself but I couldn't make sense of it) when defining the title method, it was given a 'self' argument. I.e, in my head I thought the print result code did this:

print(instance_2.title(instance_2))

So 1 argument was required by the method and one was given. I decided to find out how many arguments the title() method actually took by purposefully adding in an extra argument, to see the error message.

instance_2=str()
result=instance_2.title(instance_2)
print(result)

Here, I figured that I would get an error saying I have given 2 positional arguments but title() only takes 1.

Instead, I got this.

TypeErrorTraceback (most recent call last)
<ipython-input-1-a25ae25c09cc> in <module>()
      1 instance_2=str()
----> 2 result=instance_2.title(instance_2)
      3 print(result)

TypeError: title() takes no arguments (1 given)

My concerns are why it says I only gave 1 argument when in the very first case, I have none and it still said I gave 1, I assumed 1 was always given by default. This is apparently not so. I even tried doing the same thing (adding an extra argument) to my first code):

class NewList(DQ):
    def first_method():
        print("hello")

instance=NewList()
instance.first_method(instance)

This was the error(skipped the fluff at the start)

TypeError: first_method() takes 0 positional arguments but 2 were given

So there is clearly an extra argument being given here. Why isn't this same phantom argument coming up in the string case?

Kishan Patel
  • 778
  • 11
  • 26
Vishal Jain
  • 443
  • 4
  • 17
  • I think this question could be better received if you got a better understanding of [self](https://stackoverflow.com/questions/2709821/what-is-the-purpose-of-self) in general and asked a more focused question about the weirdness going on with `str`. I agree that it's a little weird –  Jun 28 '19 at 11:44
  • I'm not sure how relevant this is to what you're seeing, but bear in mind that the `str` methods are implemented in C, not Python –  Jun 28 '19 at 11:44

1 Answers1

0

title is implemented like the staticmethod descriptor, so it will work on both the str class and any of it's instance. But when it's called from str class, it needs one addition parameter -- the string to operate on.

In your case, you've made first_method an unbound function that can only be called as a class attribute. It can't be called from instance, as once you do instance.first_method() Python implicitly pass the instance (self in the usual term) as the first argument at runtime, but the function does not take any argument hence the error.

If you want to make it work for both class and instance, you can make it a staticmethod using the staticmethod descriptor:

class NewList():
    @staticmethod
    def first_method(cls):
        print("hello")

Now both NewList.first_method() and NewList().first_method() would work.

heemayl
  • 39,294
  • 7
  • 70
  • 76