Python 2.8 - deleting .001, .002, etc

I found several threads on this subject but could not distill a solution. I am trying to delete .001, .002, etc.

The code should delete these, but every time I rerun my code it is as if nothing was ever deleted; the count is now >0.250 and is rising rapidly.

Full disclosure: The solution below is inefficient; it is the culmination of several efforts to solve my problem and represents my final "brute force" approach.

def delete_object_iteration(objname):
for x in range(1, 999):
xs=str(x)
on2=objname+'.'+xs.zfill(3)
try:
except:
pass
delete_object_instance(on2)

def delete_object_instance(objname):
try:
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
except:
pass
try:
bpy.ops.object.select_all(action='DESELECT')
bpy.data.objects[objname].select_set(True)
bpy.ops.object.delete()
except:
pass
$$$$

• I'm a bit confused why you call delete_object_instance after you've already removed the object. Jul 29 '19 at 20:20

The following script works fast and removes the objects.

import bpy

def delete_object_iteration(obj_name):
for x in range(1, 999):
obj = bpy.context.scene.objects.get(obj_name + '.' + str(x).zfill(3))
if obj is not None:

delete_object_iteration("Cube")


The alternative approach would be using the operator with context override.

import bpy

def delete_object_iteration(obj_name):
objs = []
for x in range(1, 999):
obj = bpy.context.scene.objects.get(obj_name + '.' + str(x).zfill(3))
if obj is not None:
objs.append(obj)
bpy.ops.object.delete({"selected_objects": objs})

delete_object_iteration("Cube")


In case you don't want to remove only between 1 and 999:

import bpy

def is_match(prefix, name):
split_name = name.split('.')
if len(split_name) == 2 and split_name[0] == prefix and split_name[1].isdigit():
return True
else:
return False

def delete_object_iteration(obj_name):
for obj in bpy.context.scene.objects:
if is_match(obj_name, obj.name):

delete_object_iteration("Cube")


Purging orphans as well:

import bpy

def is_match(prefix, name):
split_name = name.split('.')
if len(split_name) == 2 and split_name[0] == prefix and split_name[1].isdigit():
return True
else:
return False

def purge_orphans():
old_type = bpy.context.area.type
bpy.context.area.type = 'OUTLINER'
bpy.context.space_data.display_mode = 'ORPHAN_DATA'
bpy.ops.outliner.orphans_purge()
bpy.context.area.type = old_type

def delete_object_iteration(obj_name):
for obj in bpy.context.scene.objects:
if is_match(obj_name, obj.name):
purge_orphans()

delete_object_iteration("Cube")

• Oops... posted without noticing you had edited answer to include similar. Jul 30 '19 at 9:52
• @batFINGER no problem. You're answer also includes variations that mine doesn't. Jul 30 '19 at 9:54

Finding with re

Alternatively, find all objects that match a pattern using active objects name. With object "Cube" active a simple re could be

regexp = r'Cube.\d+'


any object with a name starting with "Cube." and ending only with digits past that point will match. Need only iterate over scene.objects, or any collection containing objects eg all in blend bpy.data.objects, and see if they match, as opposed to finding if any of each of a 1000 exist.

There are other ways without re, eg split or rpartition on "." and test if part is numeric.

>>> "Cube.001".rpartition(".")
('Cube', '.', '001')


Test script finds the matches.

import bpy
import re

context = bpy.context
scene = context.scene
ob = context.object

rexp = f"{ob.name}.\d+"

matches = [o for o in scene.objects if re.fullmatch(rexp, o.name)]

print(matches)


Ok if we have matches, can iterate and delete from blend.

while matches:
bpy.data.objects.remove(matches.pop())


Or with the operator, passing a context override.

if matches:
bpy.ops.object.delete({"selected_objects" : matches})


There is a lot of over zealous hoo-ha re not using operators. If you had 1000s of matches above, the operator is still called only once... IMO this is Ok.

but Don't!!!! do this

for o in matches:
bpy.ops.some.op(....)


and call the operator 1000s of times.

Python performance with Blender operators

Why avoid bpy.ops?

Please also note that bpy.ops.object.select_pattern(...) has similar functionality, and this could be a 2 liner.

bpy.ops.object.select_pattern(pattern="Cube.*", extend=False)
bpy.ops.object.delete()


Which will delete "Cube.001.001" also.

• Sorry to intrude .. but this is the sort of place I'm getting stuck trying to figure out the API. The only ref. I have to bpy.ops.object.delete is this one .. I assume you're replacing a context parameter with a dictionary of your own ... where would I find the docs for that? Is context` an default parameter for all ops calls, or something? Jul 30 '19 at 12:00
• blender.stackexchange.com/questions/35653/… Would love to see the required context members in the docs. Jul 30 '19 at 12:31
• Thanks. It's nice to know I'm not he only one. With the occasional help of folks like you, I'll muddle through.. :) Jul 30 '19 at 12:49