Open Andrej730 opened 1 year ago
Hi, thanks for pointing that out and apologies for coming back so late: I wanted to write a proper reply. I also apologise in case you are already knowledgeable about the subject and find my explanation redundant.
The difference between the two statements is that ==
evaluates to True
when both sides have the same value, is
evaluates to True
when both sides are the same thing. A quick example
>>> a = "Hello"
>>> b = "Hello World"
>>> a + " World" == b
True
>>> a + " World" is b
False
But as you wrote, blender 2.78 presents this weird behavior
>>> C.object == C.object
True
>>> C.object is C.object
False
That happens because those python objects are non-unique containers. The actual blender objects are part of the C core app instead. The bpy module consists of "wrappers" that do the following:
Wrappers are written C++ and have access to blender internal entities, but they are derived from python C++ classes so they can be accessed in python scripts.
When we type C.object
in the console and press enter, blender takes the active object, puts it inside a python box and gives it to the interpreter. Now it should be clear how come the two results used to differ. When asked if
>>> C.object == C.object
python is faced with a box on the left and a box on the right. Will look in one box and then in the other: "hey they contain the same C object, so these boxes are equivalent". It returns True
.
But confronted with
>>> C.object is C.object
python doesn't bother to look inside: it's either the same box or not.
The function id() returns the memory address of a python object. Asking for the memory address of C.object repeatedly in blender 2.79 gives these results (every time different numbers, not the same as in this example)
>>> id(C.object)
1955119776328
>>> id(C.object)
1955119776136
>>> id(C.object)
1955119776904
Those would fail the is
condition, because it's a different box every time, stored at a different memory address.
At a certain release, perhaps 2.8, they improved that policy: blender keeps returning the same box.
Asking for the id
repeatedly in blender 3.x returns a consistent memory address (you will get a different number)
>>> id(C.object)
2300011633600
>>> id(C.object)
2300011633600
>>> id(C.object)
2300011633600
I could not find the exact change in the source, but I have talked with the developers and they assured me that, from blender 3 on, the identity between selected_object[i]
and C.object
holds.
I admit that using identity in my example would have required such explanation, and in the hindsight I should have rather used ==
.
Now I would rather not change the accompanying code in order not to confuse the reader, but I'll mention the alternative in a comment. In the meantime, I hope that this explanation can be somehow beneficial
Kind Regards, Paolo
Yeah, makes sense, thank you.
Some benefit of is
that it could be slightly faster too since it's just comparing python objects ids instead of looking up original objects. But it's probably barely noticeable.
Noticed that in the snippet below objects are compared using
is
, not==
.Though the exact code works wanted to put it out there that it used to lead to issues. It's seems better now but haven't seen Blender mentioning anywhere that it was resolved completely so it could be still more safe to use
==
to make sure it's the same object, notis
.https://github.com/PacktPublishing/Python-Scripting-in-Blender/blob/a9aabf003078baa311c8d25890702ef4e6fe9f33/ch2/0500_understanding_user_context.py#L44-L48