Reputation: 9977
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
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
Reputation: 9977
Props to everyone that led me there in the comments section.
The answer to this question rely on two fundamentals of Python:
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