0

Consider the following code, I expected it to generate error. But it worked. mydef1(self) should only be invoked with instance of MyClass1 as an argument, but it is accepting MyClass1 as well as rather vague object as instance.
Can someone explain why mydef is accepting class name(MyClass1) and object as argument?

class MyClass1:

    def mydef1(self):
        return "Hello"

print(MyClass1.mydef1(MyClass1))
print(MyClass1.mydef1(object))

Output

Hello
Hello
Tejas Sarade
  • 1,144
  • 12
  • 17

4 Answers4

1

Python is not a statically-typed language, so you can pass to any function any objects of any data types as long as you pass in the right number of parameters, and the self argument in a class method is no different from arguments in any other function.

blhsing
  • 91,368
  • 6
  • 71
  • 106
1

Python is dynamically typed, so it doesn't care what gets passed. It only cares that the single required parameter gets an argument as a value. Once inside the function, you never use self, so it doesn't matter what the argument was; you can't misuse what you don't use in the first place.

This question only arises because you are taking the uncommon action of running an instance method as an unbound method with an explicit argument, rather than invoking it on an instance of the class and letting the Python runtime system take care of passing that instance as the first argument to mydef1: MyClass().mydef1() == MyClass.mydef1(MyClass()).

chepner
  • 497,756
  • 71
  • 530
  • 681
  • It is rather weird, the method is indeed accepting whatever I pass. I just wanted to run the method without creating any instance. – Tejas Sarade Jun 29 '18 at 19:21
  • 2
    I wouldn't say it's weird; if anything, `a.mydef1()` is magic syntactic sugar for making the expected "canonical" call `MyClass1.mydef1(a)` work in the face of inheritance. – chepner Jun 29 '18 at 19:23
1

There are several parts to the answer to your question because your question signals confusion about a few different aspects of Python.

First, type names are not special in Python. They're just another variable. You can even do something like object = 5 and cause all kinds of confusion.

Secondly, the self parameter is just that, a parameter. When you say MyClass1.mydef1 you're asking for the value of the variable with the name mydef1 inside the variable (that's a module, or class, or something else that defines the __getattr__ method) MyClass1. You get back a function that takes one argument.

If you had done this:

aVar = MyClass1()
aVar.mydef1(object)

it would've failed. When Python gets a method from an instance of a class, the instance's __getattr__ method has special magic to bind the first argument to the same object the method was retrieved from. It then returns the bound method, which now takes one less argument.

I would recommend fiddling around in the interpreter and type in your MyClass1 definition, then type in MyClass1.mydef1 and aVar = MyClass1(); aVar.mydef1 and observe the difference in the results.

If you come from a language like C++ or Java, this can all seem very confusing. But, it's actually a very regular and logical structure. Everything works the same way.

Also, as people have pointed out, names have no type associated with them. The type is associated with the object the name references. So any name can reference any kind of thing. This is also referred to as 'dynamic typing'. Python is dynamically typed in another way as well. You can actually mess around with the internal structure of something and change the type of an object as well. This is fairly deep magic, and I wouldn't suggest doing it until you know what you're doing. And even then you shouldn't do it as it will just confuse everybody else.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • I tried to learn Java before Python and was expecting that object oriented part would be similar in both. – Tejas Sarade Jun 29 '18 at 19:48
  • @TejasSarade - they are similar but different. Under the hood they are very different. – Omnifarious Jun 29 '18 at 19:50
  • @TejasSarade - BTW, reaching inside an object and messing around with it in really strange ways, like changing its class or adding functions to it, is called 'monkey patching' and it's generally frowned upon. But, like pointer casts in C/C++, the Python people would never remove the ability. It's core to the language. It's just not something you should do much. – Omnifarious Jul 01 '18 at 17:54
0

There is no problem with that whatsoever - self is an object like any other and may be used in any context where object of its type/behavior would be welcome.

Python - Is it okay to pass self to an external function

Dharmeshsharma
  • 683
  • 1
  • 11
  • 28