Batch-friendly bpy.ops operators and deferred view layer updates
Using
bpy.ops
in loops for creating many objects (e.g., hundreds of cubes with
bpy.ops.mesh.primitive_cube_add
) is extremely slow in Blender. Previously, Python developers could monkey-patch
_BPyOpsSubModOp._view_layer_update
since Blender 2.93 all the way to Blender 5.0 (see
this thread
) to reduce Python-side overhead, but this no longer works in Blender 5.1+. The slowdown now perhaps comes from C/C++ dependency graph updates and undo stack operations triggered by each operator, which cannot be bypassed from Python.
Use case:
-
Artists or addon developers want to create grids, arrays, or large numbers of objects using
bpy.opsfor convenience. - Current Python hacks are fragile and break in newer Blender versions.
We need a way to defer dependency graph and view layer updates when running multiple operators in a loop. This would allow bulk execution of
bpy.ops
without the per-operator performance penalty, while still keeping the convenience of the operators.
4 Comments
I’m not against this idea, but I wonder if it's the right direction to begin with?
The issue with
bpy.opsisn’t just the DG updates: it’s the whole package of context requirements, mode switching, undo stack interaction, dependency graph updates, maybe other things I don't even know about. Even if we make it possible to defer DG updates, those problems remain. It's just giving us another band-aid to keep doing things inneficiently.In practice, once a script grows beyond a few lines, you end up stacking workarounds to context overrides, handling modes, … And the initial convenience of (some) operators mostly disappears. At that point, the data API is often just as fast to write while being far more predictable and fast to execute.
Hence, a direction I personally find more interesting would be a simpler, more consistent data-oriented API. Easier said than done, of course. But if it could be done, I'd like something in the spirit of Autodesk Maya’s
cmdswhich follows a very clear “create / query / edit” pattern:So imagine creating 50 offset grid objects:
This kind of KISS design scales much better than layering abstractions over UI operators.
It also enables something Blender currently struggles with but Maya does very well:
Almost everything you do in the UI is echoed as usable commands in the script editor. That makes learning and scripting much more intuitive: you can just perform an action and get the exact code to reproduce it programmatically and efficiently.
It optionally can also show GUI-related commands like when you open/close a menu or open a new window, e.g. making it easy to know what a button does or which menu ID you need to add/remove things in it.
In contrast, Blender’s Info editor output is inconsistent and, by essence, will show operator calls that you shouldn't use programmatically and will never tell you which menu ID you just opened.
Totally agree with your point 🙂 A full data-oriented API would be ideal, but that’s a huge change. In the meantime, my API provides a practical way to speed up batch
bpy.opsoperations, especially in large loops, without relying on fragile hacks. Once a better solution exists, it can be swapped out easily.True that
Really need this! I conducted some research and discovered that the _BPyOpsSubModOp function has been removed in Blender 5.1. It appears that all control over View Layers is now managed in C++ code, meaning operations involving bpy.ops.object.* can no longer temporarily halt viewport refreshes. as the link: projects.blender.org/blender/blender/pulls/145344