3
$\begingroup$

I am trying to delete all the objects that start with 'LTR' but am getting the following error: 'tuple' object has no attribute 'name'

Any suggestions are much appreciated!

for obj in enumerate(bpy.context.scene.objects):
    namestr=obj.name #this throws the error
    if len(namestr)>=3:
        name2=namestr[3:]
        if name2=='LTR':
            delete_object(namestr) #this is a function that deletes the object
$\endgroup$
7
$\begingroup$

enumerate(iterable, start=0) returns a tuple for each element from any given iterable and its position based on the actual iteration. Proof using the Console:

>>> for i in enumerate(["Hello","World"]):
>>>     print (i)
(0, "Hello")
(1, "World") 

A tuple is a composite data type, composed out of two elements (item1, item2). If you want to access its individual components (left, right) you can either use the index operator [] or create 2 variables for the actual return value (tuple) on the fly: left, right = ("Hello", "World"):

>>> my_tuple = ("Hello", "World")
>>> my_tuple[0]
"Hello"

left, right = ("Hello", "World")
>>> left
"Hello"

Means in your case that you can't access the object and its name this way because the returned tuple by the enumerate() function in your loop has no name property. Proof using the Console again:

>>> for ob in enumerate(C.scene.objects):
...     print (ob)
(0, bpy.data.objects['Cube'])
(1, bpy.data.objects['Light'])
(2, bpy.data.objects['Camera'])

In summary: you have to find a way splitting the components of the tuple if you want to access each element separately which basically leads into the following pattern:

>>> for left, right in enumerate(C.scene.objects):
...     print (left, right, "Name:", right.name)
0 <bpy_struct, Object("Cube")>, Name: Cube
1 <bpy_struct, Object("Light")> Name: Light
2 <bpy_struct, Object("Camera")> Name: Camera

Also notice that python has a lot of awesome tools dealing with strings. In order to determine whether a string is part of a another string (substring), you could use the in operator to test its "membership":

>>> "ell" in "HelloWorld"
True

To remove the objects, you might want to create some kind of black list before removing it. The following example removes all objects in the scene that have "Cam" in their name (substring):

import bpy

objects_to_remove = []

for ob in bpy.context.scene.objects:
    if "Cam" in ob.name:
        objects_to_remove.append(ob)

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

There is also str.startswith(prefix) returning True if the string begins with the prefix passed:

>>> "Hello World".startswith("Hell")
True

The following example removes all found objects whose names begin with "Cam":

import bpy

objects_to_remove = []

for ob in bpy.context.scene.objects:
    if ob.name.startswith("Cam"):
        objects_to_remove.append(ob)

bpy.ops.object.delete({"selected_objects": objects_to_remove})
$\endgroup$
5
$\begingroup$

When you use enumerate, an item in the list and an index/counter of where you are in the loop is returned to the variable (obj) instead of just the item. This is why you get the error, because in this case obj is a tuple ((index, listItem)) which does not have a name property itself.

The common loop syntax when using enumerate is:

for index, obj in enumerate(bpy.context.scene.objects):

obj will now contain the actual object as expected.

However, if you don't need an index of where you are in the loop you do not need to use enumerate. Remove it and it will work fine, e.g.:

for obj in bpy.context.scene.objects:

You could also access the second item in the tuple when trying to access the name:

namestr=obj[1].name
$\endgroup$

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.