Most operators cause implicit scene updates. It means that every object in the scene is checked and updated if necessary. If you add e.g. mesh primitives using bpy.ops.mesh.primitive_cube_add()
in a loop, every iteration creates a new cube, starts a scene update and Blender iterates over all objects in the scene and updates objects if it has to.
If you start with 0 objects, there will be 1 in the first iteration and 1 object needs to be checked in the scene update. In the second iteration, there will be 2 objects and 2 be checked. The first object was checked in the first iteration already (thus, 3 object updates in total). In the third iteration, there will be 3 objects and 3 + 2 + 1 = 6 objects checked in total. In iteration 1000, there will be 1000 objects and 500,500 checks have been carried out. Here's the formula where n
is the number of objects:
$\displaystyle \sum_{n=1}^n i = 1 + 2 + ... + n = \frac {n (n + 1)} {2} $
As you see, the runtime isn't linear and could only be if there was only one update for every object after all have been added. You need to use the "low-level" API - RNA methods and attributes - instead of operators to achieve better runtimes. A scene update needs to be called manually like bpy.context.scene.update()
with this approach.
Many, but not all operator calls can be somehow replaced by "low-level" code. You can duplicate objects very efficiently like:
import bpy
from mathutils import Vector
ob = bpy.context.object
obs = []
sce = bpy.context.scene
for i in range(-48, 48, 3):
for j in range(-48, 48, 3):
copy = ob.copy()
copy.location += Vector((i, j, 0))
copy.data = copy.data.copy() # also duplicate mesh, remove for linked duplicate
obs.append(copy)
for ob in obs:
sce.objects.link(ob)
sce.update() # don't place this in either of the above loops!
A good comparison between 4 different ways to do the same thing:
bpy.ops.anim.keyframe_insert_menu()
- don't ever use this in a script, it is solely to show a menu for the user
bpy.ops.anim.keyframe_insert()
- this is supposed to be used via the UI, not in script. Use operator calls only if there is no lower-level API!
Object.keyframe_insert() - RNA method that can be called on an object, better
The low-level way - add F-Curves and keyframe_points
manually, fastest but you need to do alot yourself and consider several conditions (like object not having animation_data
or an animation_data.action
)
Related (also examples included):