Simple and maybe stupid question:
I was reading this lot of time, that
"you should avoid using
bpy.ops, or "instead of
bpy.ops, use this and that"...
So why is that? Is that buggy, or what?
bpy.ops operators depend on the context (selected objects, active shape key index, etc.), therefore I think some are more suitable to be used interactively than in a script.
bpy.ops judiciously rather than avoiding it wholesale. For example, I find creating constraint through a posebone's
constraints.new easier to read, and independent from context, compared to changing context then calling
bpy.ops can be indispensable for some tasks like vertex group manipulation and file operation even though it means temporarily messing with context.
For me, it really depends on what you're trying to do. Before resorting to
bpy.ops.*, see if the task can be accomplished in any other way. Using
bpy.ops operators may not always be best, but careful application can still result in readable code and smooth user interaction.
I'll just quote ideasman42:
When possible I would avoid using bpy.ops, These wrap tools in a way that relies on the context and dont have a good way to pass args and return results to scripts. If there is an alternative (as with bmesh), it's better integrated into python, and you don't have to worry about active object, modes, visible layers etc.
bpy.ops may boost performance of your scripts when manipulating lots of objects. See: Python performance with Blender operators
Apart from what's been said already, operators also create undo steps. This means that every time you execute an operator, the entire blend file is saved in memory. This is one of the reasons calling an operator is much slower than the corresponding alternative function calls.
This is also why it's a good idea to, when writing an operator, place the major part of the code into regular Python functions, and call those from the operator code. This allows others to import your module and call those functions as well, from their own code.