scharette
scharette

Reputation: 9977

Calling instance method using class definition in Python

Lately, I've been studying Python's class instantiation process to really understand what happen under the hood when creating a class instance. But, while playing around with test code, I came across something I don't understand.

Consider this dummy class

class Foo():

    def test(self):
        print("I'm using test()")

Normally, if I wanted to use Foo.test instance method, I would go and create an instance of Foo and call it explicitly like so,

foo_inst = Foo()
foo_inst.test()
>>>> I'm using test()

But, I found that calling it that way ends up with the same result,

Foo.test(Foo)
>>>> I'm using test()

Here I don't actually create an instance, but I'm still accessing Foo's instance method. Why and how is this working in the context of Python ? I mean self normally refers to the current instance of the class, but I'm not technically creating a class instance in this case.

print(Foo()) #This is a Foo object
>>>><__main__.Foo object at ...>
print(Foo) #This is not
>>>> <class '__main__.Foo'>

Upvotes: 5

Views: 1624

Answers (2)

blue note
blue note

Reputation: 29061

A few notes on your question (and answer). First, everything is, really an object. Even a class is an object, so, there is the class of the class (called metaclass) which is type in this case.

Second, more relevant to your case. Methods are, more or less, class, not instance attributes. In python, when you have an object obj, instance of Class, and you access obj.x, python first looks into obj, and then into Class. That's what happens when you access a method from an instance, they are just special class attributes, so they can be access from both instance and class. And, since you are not using any instance attributes of the self that should be passed to test(self) function, the object that is passed is irrelevant.

To understand that in depth, you should read about, descriptor protocol, if you are not familiar with it. It explains a lot about how things work in python. It allows python classes and objects to be essentially dictionaries, with some special attributes (very similar to javascript objects and methods)

Regarding the class instantiation, see about __new__ and metaclasses.

Upvotes: 2

scharette
scharette

Reputation: 9977

Props to everyone that led me there in the comments section.


The answer to this question rely on two fundamentals of Python:

  1. Duck-typing
  2. Everything is an object

Indeed, even if self is Python's idiom to reference the current class instance, you technically can pass whatever object you want because of how Python handle typing.

Now, the other confusion that brought me here is that I wasn't creating an object in my second example. But, the thing is, Foo is already an object internally.

This can be tested empirically like so,

print(type(Foo))
<class 'type'>

So, we now know that Foo is an instance of class type and therefore can be passed as self even though it is not an instance of itself.

Basically, if I were to manipulate self as if it was a Foo object in my test method, I would have problem when calling it like my second example.

Upvotes: 2

Related Questions