26
$\begingroup$

How can I completely remove an object (for example a camera) using python scripting?

Using something like:

scene.objects.unlink(camera)

Does not work, since it is still available in bpy.data.objects. However, using:

bpy.data.objects.remove(camera)

still doesn't remove the camera, since it continues to exists in bpy.data.cameras.

Is there a way to remove an object from all of these places at the same time?

$\endgroup$
  • 5
    $\begingroup$ camera is actually an object datablock, not a camera. You need to unlink the object from the scene, delete the camera (ob.data, which would be camera.data in your example) and finally delete the object. If not possible to remove datablocks if they have users however, and clearing the user count may lead to crashes later on - thus it's advisable to use the delete operator instead. $\endgroup$ – CoDEmanX Mar 17 '15 at 13:21
37
$\begingroup$

You can use bpy.ops.object.delete() operator to remove selected objects:

import bpy

# Deselect all
bpy.ops.object.select_all(action='DESELECT')

# Select the object
bpy.data.objects['Camera'].select = True    # Blender 2.7x

# https://wiki.blender.org/wiki/Reference/Release_Notes/2.80/Python_API/Scene_and_Object_API
bpy.data.objects['Camera'].select_set(True) # Blender 2.8x

bpy.ops.object.delete() 

In order to remove multiple objects, you can iterate through all objects, set the select state in Blender 2.7x or call select_set(state) in Blender 2.8x based on a certain condition and finally call the operator one time.

Blender 2.7x

import bpy

# Delect objects by type
for o in bpy.context.scene.objects:
    if o.type == 'MESH':
        o.select = True
    else:
        o.select = False

# Call the operator only once
bpy.ops.object.delete()

# Save and re-open the file to clean up the data blocks
bpy.ops.wm.save_as_mainfile(filepath=bpy.data.filepath)
bpy.ops.wm.open_mainfile(filepath=bpy.data.filepath)

Blender 2.8x

import bpy

# Select objects by type
for o in bpy.context.scene.objects:
    if o.type == 'MESH':
        o.select_set(True)
    else:
        o.select_set(False)

# Call the operator only once
bpy.ops.object.delete()

# Save and re-open the file to clean up the data blocks
bpy.ops.wm.save_as_mainfile(filepath=bpy.data.filepath)
bpy.ops.wm.open_mainfile(filepath=bpy.data.filepath)

Context override (2.7x & 2.8x)

Instead of (de)selecting the object(s) beforehand, you can also pass a custom context (a list of objects in this case) to avoid changing the selection within the viewport:

import bpy

objs = [bpy.context.scene.objects['Camera'], bpy.context.scene.objects['Cube']]
bpy.ops.object.delete({"selected_objects": objs})

Example on how to remove objects by certain types:

import bpy

objs = [ob for ob in bpy.context.scene.objects if ob.type in ('CAMERA', 'MESH')]
bpy.ops.object.delete({"selected_objects": objs})

Further reading: https://docs.blender.org/api/current/bpy.ops.html#overriding-context

$\endgroup$
  • 2
    $\begingroup$ Ah, good to know, then thats the information I was missing! $\endgroup$ – Jan Rüegg Mar 17 '15 at 12:48
  • 1
    $\begingroup$ if before that you had selected some other object, it will also be selected and then removed... $\endgroup$ – ntg Aug 25 '16 at 16:11
  • 1
    $\begingroup$ @ntg Yep, that's the nature of the operator and also mentioned in the answer ...remove selected objects. What's your question? How to avoid that behavior? $\endgroup$ – p2or Aug 25 '16 at 16:37
  • 1
    $\begingroup$ @poor: No question, just an observation.... Running bpy.ops.object.select_all(action='DESELECT') beforehand will deselect everything, "avoiding" it. $\endgroup$ – ntg Aug 26 '16 at 8:13
  • 1
    $\begingroup$ @ntg You can set the objects select flag to False for certain objects in the scene/context. For more control go with a for loop instead (for ob in bpy.data.objects: ob.select = False), which does basically the same as the operator, but allows for instance to exclude objects in order to "avoid" re-selecting ;) $\endgroup$ – p2or Aug 26 '16 at 9:39
24
$\begingroup$

This can be done without using ops which makes it much faster then using the ops call.

Buried deep in the documentation is the remove function.

import bpy
objs = bpy.data.objects
objs.remove(objs["Cube"], do_unlink=True)

The first parameter of the remove function is the object to remove (in this case the default "Cube"), the second is a boolean about first unlinking the object.
If you run objs.remove(objs["Cube"]) with the cube sitting in your 3D view you will get an error:

RuntimeError: Error: Object 'Cube' must have zero users to be removed, found 1 (try with do_unlink=True parameter)

See this remove function only deletes data with no users. That is why you have to explicitly tell it to first unlink the object then delete it.

$\endgroup$
  • 3
    $\begingroup$ note that this will work in 2.77 and higher only. prior vers have no do_unlink. :-/ $\endgroup$ – Mechanic Sep 5 '17 at 4:43
7
$\begingroup$

Just to add up to the great answer above, one must be in OBJECT mode in order to delete objects. In order to do so in Python use the following code:

bpy.ops.object.mode_set(mode='OBJECT')

It also makes sense to return to previous mode, after the operation:

oldMode = bpy.context.mode
bpy.ops.object.mode_set(mode='OBJECT')
 ...Select your object here
bpy.ops.object.delete()
bpy.ops.object.mode_set(mode=oldMode)
$\endgroup$
5
$\begingroup$

You can do this:

item='CAMERA'
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_by_type(type=item)
bpy.ops.object.delete()

where item can take any of the following values according to this documentation:

[‘MESH’, ‘CURVE’, ‘SURFACE’, ‘META’, ‘FONT’, ‘ARMATURE’, ‘LATTICE’, ‘EMPTY’, ‘CAMERA’, ‘LAMP’, ‘SPEAKER’]

The above method works, but is not ideal. The following method works and is ideal. First remove the meshes with the following code:

for obj in bpy.context.scene.objects:
     if obj.type == 'MESH':
         obj.select = True
     else:
         obj.select = False
 bpy.ops.object.delete()

Then you can execute the following code snippet to remove all the unused blocks. This way you don't have to close/open Blender or save/open a .blend file:

for block in bpy.data.meshes:
    if block.users == 0:
        bpy.data.meshes.remove(block)

for block in bpy.data.materials:
    if block.users == 0:
        bpy.data.materials.remove(block)

for block in bpy.data.textures:
    if block.users == 0:
        bpy.data.textures.remove(block)

for block in bpy.data.images:
    if block.users == 0:
        bpy.data.images.remove(block)

IMPORTANT NOTE: It looks like that there is some dependencies between some data blocks such as mesh, texture, image and materials. If you do not remove the data blocks on the highest level of the hierarchy, you will not be able to remove other data blocks or you have to take the risk and remove data blocks with users more than 0. So make sure you use the code above in the following order to remove data blocks. This way you can remove all unlinked (users == 0) data blocks:

remove meshes --> remove materials --> remove textures --> remove images

The followings also have data blocks:

bpy.data.curves
bpy.data.lamps
bpy.data.cameras
$\endgroup$
  • $\begingroup$ This is more relevant for preventing memory leakage in Blender $\endgroup$ – Amir Mar 1 '18 at 4:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.