Why class 1 instance 1's method is not class 1 instance 2's method? 🐍 | Sololearn: Learn to code for FREE!
New course! Every coder should learn Generative AI!
Try a free lesson
+ 8

Why class 1 instance 1's method is not class 1 instance 2's method? 🐍

I thought it would be crystal clear that all instances of the same class would dynamically share their methods. 💎 For example if we had class A, with method f, and if we created instances a and b, a.f(args) would translate into A.f(a, args) and b.f(args) into A.f(b, args), both objects would have used the 1 same method with just different arguments, that's how I've so far understood it, but... 😶 ⏬ Why a.f is not b.f? 🕵 In the code 📋 you can see that a.f is b.f evaluates to False: https://code.sololearn.com/crRFN7NjjV7x/?ref=app

4th Nov 2019, 6:30 PM
Seb TheS
Seb TheS - avatar
38 Answers
+ 5
They are equal, yet different objects. a and b reffer to two different created objects, even if they are the same. Try equaling them, 'is' operator checks, whether both variables reffer to one value. a == b, but a is not b.
4th Nov 2019, 6:47 PM
Asman-H
Asman-H - avatar
+ 5
🌟Prometheus 🇸🇬, it makes no difference, it happens with an instance method as well. The point is that a.f.__func__ is C.f. So the instance's f is not the same as the class's f, but it just *stores* the class's f! But when you use id on the instances's f, you get the same id. My guess would be that __hash__ is just set up in a way to return __func__'s id instead?
5th Nov 2019, 12:09 AM
HonFu
HonFu - avatar
+ 4
You've created a class method. Class methods and static methods are different. A class method takes cls as first parameter while a static method needs no specific parameters.  Theory: This probably means the class instances used are probably different but the functions point to the same object.
4th Nov 2019, 11:56 PM
👑 Prometheus 🇸🇬
👑 Prometheus 🇸🇬 - avatar
+ 4
Wow... great discussion guys... I came to the same conclusion you guys reached by building this really messy script. https://code.sololearn.com/ck5hZkVYq7YF/ Based on my review in this script, I agree with the following conclusions stated here already: - a.f() is a wrapper function on the object `a` that passes a reference of itself when invoking A.f(a). - Class instance methods implements its __eq__ comparison operators using __hash__() rather than just id(). I suspect the hash is based on the id() of the class instance and the id() of the functions which would be consistent with everyone's observations. Thanks again for the great discussion.
6th Nov 2019, 8:22 AM
David Carroll
David Carroll - avatar
+ 3
~ swim ~ Somehow I missed that, thanks, your activity to this post was helpful anyways.
4th Nov 2019, 7:54 PM
Seb TheS
Seb TheS - avatar
+ 3
~ swim ~, in a place like this, irony can be very dangerous. 😏
5th Nov 2019, 12:39 PM
HonFu
HonFu - avatar
+ 3
Okay, I have read up a bit about methods. This is what I make of it - and I hope I'm getting it right. When you access a method, what happens is this: You get a method object that stores a reference to the class function (__func__). And when you call it, your method call a.f() is translated by the method object into C.f(a). So basically, the identity of this method object is not really important, because they all do the same. And what do we know about Python in other cases, like with immutable types? What looks in the code as two zeros, might actually be only one zero in memory. Now run this snippet: class C: def f(self): pass c = C() d = C() print(id(c.f), id(d.f)) a = c.f b = d.f print(id(a), id(b)) Funnily, in the first print statement, we have the same id. Obviously Python does aforementioned memory trick and lumps both method objects together as one, because they do the same thing anyway. But the second print gives different ids, because you created the method objects independently.
5th Nov 2019, 1:00 PM
HonFu
HonFu - avatar
+ 3
I think the reason for id([]) == id([]) to be True could be about left side list to be destroyde before right side list is even passed to the id function. This code the strengthen my hypothesis: https://code.sololearn.com/cH1GrxpM5JGe/?ref=app
5th Nov 2019, 7:08 PM
Seb TheS
Seb TheS - avatar
+ 3
~ swim ~ In id([]) == id([]) the operands were just integer or what did you mean?
5th Nov 2019, 7:21 PM
Seb TheS
Seb TheS - avatar
+ 3
This is to strengthen the theory that the lists got destroyed when id function calls terminated: https://code.sololearn.com/c5cXnaKVKavD/?ref=app
5th Nov 2019, 7:26 PM
Seb TheS
Seb TheS - avatar
+ 3
Seb TheS You convinced me too. Thanks for you explanation! However, I still have a question. If id really refers to a memory location, then in your example, it means that the python'GC works directly after an object is deleted. Else, that memory location can't be reused directly, but after a few moment, right?
5th Nov 2019, 7:55 PM
Théophile
Théophile - avatar
+ 3
Théophile Théophile I don't actually know much about when garbage collection does its work. But by: https://code.sololearn.com/c14KRJbbAbLu/?ref=app It seems that id refers to the memory location.
5th Nov 2019, 8:15 PM
Seb TheS
Seb TheS - avatar
+ 2
Object's don't share methods, they share the class. They can ACCESS each other's methods and attributes because they are in the same class. (If it's the same as Java) Edit: Nvm ignore what I said, I don't understand python.
4th Nov 2019, 6:56 PM
Odyel
Odyel - avatar
+ 2
~ swim ~ "how does compiler/interpretor knows which object method is to be called" By passing the instance to the self parameter.
4th Nov 2019, 7:25 PM
Seb TheS
Seb TheS - avatar
+ 2
In fact, a.f and b.f are definitely two different functions. f is considered as an attribute. Looking at the bytecode, we see that 'a.f is b.f' loads f as an attribute ('LOAD_ATTR') of object a / b. However, doing id(a.f) == id(b.f) will return True. I don't know if it is the good explanation but I think that since you don't decorate or change the code inside f function, a.f and b.f are bound to the same function. https://code.sololearn.com/cI3nfJBctpQE/?ref=app
4th Nov 2019, 8:31 PM
Théophile
Théophile - avatar
+ 2
~ swim ~ The thing I don't understand is why : - a.f is b.f #False - id(a.f) == id(b.f) #True Where 'is' operator should work the same way as comparing ids of a.f and b.f. Have you got an answer? (I probably misunderstood how 'is' operator works)
4th Nov 2019, 9:50 PM
Théophile
Théophile - avatar
+ 2
A riddle for you guys - try this: class C: def f(): pass a, b = C(), C() print(a.f.__func__ is b.f.__func__)
4th Nov 2019, 11:50 PM
HonFu
HonFu - avatar
+ 2
Théophile, yeah, id is supposed, at least in Cpython, to just return the address. It remains a bit strange, right? If a. f and b.f are not identical, which would make sense, since they're the instances 'containers' for C.f, the id should also be different. That's why I thought the id call was 'redirected' somehow, but it seems you can't redefine what id does. https://stackoverflow.com/questions/16153501/JUMP_LINK__&&__python__&&__JUMP_LINK-what-is-the-object-method-of-built-in-id
5th Nov 2019, 9:15 AM
HonFu
HonFu - avatar
+ 2
That's just like: A=[1,2] B=A.copy() C=A.copy() B is C => False
5th Nov 2019, 1:07 PM
Qasem
+ 2
It is a bit funny, though. The official rules go like this: If it doesn't matter (immutables), objects may be allowed to fall together into one, while when it does matter (mutables) the instances *have to* be individual. Now if I run this code... print(id([]), id([])) print(id(list()), id(list())) ... in the first example I get two times the same id, although we have two lists here. It even happens when you fill them up. By explicitly using the constructor ('new'), you get two ids. Even if it doesn't make a difference, I would have assumed that Python wouldn't be allowed to meld the two lists.
5th Nov 2019, 1:55 PM
HonFu
HonFu - avatar