Return objects with a given custom property without iterating through all objects (solved)

Working with a large number of objects (enough to create performance issues) and planning on assigning custom properties to them at unpredictable, disconnected intervals. Would like to return a list of any “tagged” objects in the scene rapidly. Ideally the implementation would involve a process similar to an SQL-like WHERE statement.

Pseudocode

some_object["custom_tag"] = 1
bpy.data.objects.get("custom_tag")

Update
This is the current solution:

objs_list = [obj for obj in bpy.data.objects if "custom_tag" in obj]

Your first line would set the custom tag, so:

obj["custom tag"] = 1

sets the Custom Property “custom tag” to 1

To get “custom tag” you would you would use something like this:

var = obj["custom tag"]

To see if “custom tag” is there you would use:

if "custom tag" in obj:
    # Do something...
    if obj["custom tag"] == 1:
        # Do something else...

To get a list of objects with Custom Property of “custom tag” you would do this:

objs_list = [obj for obj in bpy.data.objects if "custom tag" in obj]

You can refine this to only look at selected objects like this:

objs_list = [obj for obj in bpy.context.view_layer.objects.selected if "custom tag" in obj]

Hope this helps you.

objs_list = [obj for obj in bpy.data.objects if "custom tag" in obj]

is iteration, no?

The selected objects bit doesn’t help as selected object’s state will be changing. The purpose of the property was to avoid persisting or tracking the objects.

It builds a list based upon a query, not via an iteration through the objects.

So something like:

obj_list = []
for obj in bpy.data.objects:
    if "custom tag" in obj:
        obj_list.append(obj)

Would be an iteration and far less efficient.

You still need to generate your list of objects somehow, surely. This list, as defined in my first post, will auto update if you change the custom property as you process the objects BTW.

1 Like

Ah, then yes, this is what I’m looking for.

1 Like

Can you store them in a list or dict while assigning the properties? That’s what I usually do. Then I can use the appropriate list later without having to sift through all the chaff.

That was my initial thought. But not easily - nor is it necessary. TLDR, instantiating/using that list proved complicated since I needed access across multiple modules & unpredictable state changes. This prop helps avoid all that. For more details, see this solution based off this discussion and another.

Fair enough! Without knowing more about what you’re trying to do, I can’t suggest anything that clockmender hasn’t already made an excellent example of.

1 Like

Yeah it’s been a tough to communicate the nuances. Thanks for taking a crack at it.

@Zollie: This line:

objs_list = [obj for obj in bpy.data.objects if "prop_name" in obj and obj["prop_name"] == 1]

in your code over on StackExchange may return an error if the object does not have the custom Property “prop_name”, you might be better with this:

objs_list = [obj for obj in bpy.data.objects if "prop_name" in obj]
set_objs_list =  [obj for obj in objs_list if obj["prop_name"] == 1]

That way you make sure the Customer Property exist first, I haven’t tested your combined query, but it raised a quick flag, that it might not work, I may be wrong of course, it may be OK… Just test it with some objects that don’t have the Custom Property “prop_name”.

Had the same thought. It’s tested - works without error. Ended up going with your initial logic though and just deleting the property when unassigning objects

1 Like

I would assume that Python, like the vast majority of other modern programming languages, has boolean short-circuiting. The second conditional of the and expression won’t be evaluated if the first conditional evaluates to false. IOW, no errors for objects without the property.

Unless you are referring to some nuance of Python that I’m not familiar with…

1 Like

I would hope so, but it was worth checking that this is true.

I hate to be a downer, but…

obj_list = [] for obj in bpy.data.objects: if "custom tag" in obj: obj_list.append(obj)

is exactly equivalent (and not more efficient) than

objs_list = [obj for obj in bpy.data.objects if "custom tag" in obj]

True, but your first line would not be allowed in a Blender extension. Lumping multiple statements in one line is severely frowned upon! Check pep8 compliance…

Thanks any way and welcome to DevTalk.