Dunders in Blender
Blender’s Python API lets you manipulate data like objects, materials, etc. in a blend file. But, have you ever wondered what would happen if you called the add operator +
on two objects? Or when you multiply *
an object by a number?
Of course, Blender would throw an error saying unsupported operand types. 🙂
But, if you think about it, whenever you call an operator like the +
operator, Python is calling the respective double underscore method.
Blender throws an error because the Object
class, bpy.types.Object
, doesn’t implement multiplication or addition. But, this doesn’t mean Blender forbids us from adding this functionality to objects.
Just think about for a second what multiplying an object with an integer would mean in Blender’s context? 🤔
…
Of course, the closest thing we can relate to is duplicating an object. Multiplying an object by an integer should duplicate it that many times.
Lets try it out!
Duplicate objects using multiply operator
Have a look at this code snippet.
Here, the function duplicate_ntimes
duplicates a given object, self
, n times based on the second argument, other
. But, if you notice the last line, you can see that we are assigning this function as the __mul__
method to bpy.types.Object
.
Setting the __mul__
method using setattr adds it to the bpy.types.Object class so that next time when we multiply an object with an integer, this method will be invoked.
Now you can simply duplicate an object n times like this:
By the way, don’t forget to add these imports. Otherwise this code snippet will raise an error.
import bpy
from bpy import context
Contextual behaviour using context managers
Okay, implementing multiplication was pretty easy. Now, lets park that for a moment and shift our focus to addition. Think about what addition could mean in Blender’s context.
The Join operation right? 😃
But, wait. What about booleans? Addition could also mean Boolean Union. Does that mean we have to choose one over the other? 🤔 Is there a way to have both?
There is a mechanism built into Python to handle issues like this. It’s called a context manager (different from Blender’s bpy.context
) and you have definitely seen or used it before.
Anytime you read a file using the with
statement, you are using a context manager. Context managers enable us to set something up, yield the execution to other statements, and eventually tear down the initial setup.
When reading a file using the with statement, the setup is opening the file. Then you do something else, and finally, the file is closed for you. This setup and teardown is handled using __enter__
and __exit__
methods respectively.
But, implementing something using these methods means writing a class and I am personally not fond of classes. 🙂
Python has yet another mechanism to solve this. It’s called contextlib
– a standard library module to make the process of implementing context managers as simple as writing a function.
Simply import contextlib
and try the following snippet:
In the above snippet, you can see we are defining a function called zbool
which in turn defines the __iadd__
method and adds it to bpy.types.Object
. The __iadd__
method is responsible for the +=
operator.
If you notice, after we use setattr
, we are yielding control back to the user to do something. In this case, it is to use the +=
operator.
And once the user is done, we delete the __iadd__
attribute from the bpy.types.Object
class. This way, the +=
operator performs a Boolean Union only inside this zbool
context manager.
And we make this function as context manager using the decorator @contextlib.contextmanager
from the contextlib
.
Now, you perform Boolean Union operations simply like this:
By the way, those cubes were produced by the previous multiply operation. 🙂
This way we can implement contextual behaviours for our operators.
And, that’s it for now.
Conclusion
A few things you can try:
- Try implementing the join operation when
+=
is called outside the context manager. - Think of what operators like
==
,!=
,!
,/
, etc. could mean in Blender.
Read more about Python’s double underscore methods in the Python documentation.
Learn more about Python’s advanced features from this talk by James Powell.
Subscribe to my newsletter
Join other Technical Artists, Developers and CG enthusiasts who receive my latest posts on Blender, Python, scripting, computer graphics and more directly to their inbox.