Understanding How to Use Blender Python Properties

To code in Blender, it is essential to understand Blender Python Properties. However, when I started working with Blender, I found properties to be confusing. From the way that properties were declared to the types of properties (specifically enum) to the UI display of properties. Therefore, I put together this deep dive guide to properties. Please let me know in the comments if there is anything that I left out.

What are Properties?

Almost every setting in Blender is a property. In fact, the default section on the bottom right of the window is labeled “Properties”.

Blender Property Panel in lower right corner of Blender window.
Blender Property Window

Access to any of the properties in Blender is easy. You can simply right click on the property and click either copy full data path (which copies the data path for the currently selected object), or click copy data path (which just copies the name of the property).

To access the full data path of a property, right click on the property
Accessing the Full Data Path

However, there are circumstances where we may want to add our own property. For example, we may want to add a speed property that controls how fast an object moves in an animation or we may want to add a tag to objects that allows us to categorize and filter objects in a complex scene. We can do this through the Blender Python API, specifically Blender Python Properties, which, according to the API reference, “extend Blender’s internal data.”

The Basics: How to use Blender Python Properties

Now back to properties. In basic cases, Blender Python properties are easy to use. You can create them as part of an operator or as part of another datablock (like and object or a scene). 

Creating a Property in an Operator

Below is the code from the Blender API reference.

class OBJECT_OT_property_example(bpy.types.Operator):
    bl_idname = "object.property_example"
    bl_label = "Property Example"
    bl_options = {'REGISTER', 'UNDO'}

    my_float: bpy.props.FloatProperty(name="Some Floating Point")
    my_bool: bpy.props.BoolProperty(name="Toggle Option")
    my_string: bpy.props.StringProperty(name="String Value")

    def execute(self, context):
        self.report(
            {'INFO'}, 'F: %.2f  B: %s  S: %r' %
            (self.my_float, self.my_bool, self.my_string)
        )
        print('My float:', self.my_float)
        print('My bool:', self.my_bool)
        print('My string:', self.my_string)
        return {'FINISHED'}
Python

In this example, we define the properties:

my_float: bpy.props.FloatProperty(name=”Some Floating Point”)
Python

We can then access it using self.my_float to either set the value or get the value.

I found the structure to define the property to be interesting. As I noted in previous post the structure is actually a type annotation based on PEP 526.

Add Property to an Object

The example above adds the properties to an operator. You can also add them to an existing datablock in Blender. For example, to add a custom float to objects, you can add:

bpy.types.Object.myProp = bpy.props.FloatProperty(default=7)
Python

This adds a float property to every object with a default value of 7.

One thing that I think is strange about adding a property is you do not see it in the UI. It would be nice if it was automatically added to the UI (or at least in the assignment you had the ability to enable it in the UI). You can add with the following code:

import bpy

class UIListPanelExample1(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "My Properties Panel"
    bl_idname = "OBJECT_PT_ui_list_example_1"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        self.layout.prop(bpy.context.object,"my_float")

def register():
    # Clean up previous registration
    unregister()
    
    print("register ui list panel")
    bpy.types.Object.my_float = bpy.props.FloatProperty(default=0)
    bpy.utils.register_class(UIListPanelExample1)
    
def unregister():
    print("Unregistering")
    
    try:
        bpy.utils.unregister_class(UIListPanelExample1)
    except RuntimeError:
        pass
    
    try:
        del bpy.types.Object.my_float
    except AttributeError:
        pass


if __name__ == '__main__':
    register()
Python

Note that in this example, we register the property in the register function. If you are adding properties for an add-on, this is the recommended way.

📬 Enjoying this post?

Get monthly tutorials, project updates, and coding insights delivered to your inbox. No spam, unsubscribe anytime.

Types of Properties

Now that we know how to create properties, let’s discuss the types of properties. There are 10 types of properties. We will not cover all of them in detail here because several are self explanatory.

Bool, Float, Int, String

The first properties that we will discuss are the float, int, and string. These are the same as the Python variable types float, int, and string. Defining is relatively straightforward:

bpy.types.Object.boolTest = bpy.props.BoolProperty()
bpy.types.Object.floatTest = bpy.props.FloatProperty(default=7.2)
bpy.types.Object. intTest = bpy.props.IntProperty(default=7)
bpy.types.Object.stringTest = bpy.props.StringProperty(default="this is only a test")
Python

There are many options for these properties. For example, for both int and float properties, you can set the min and max for the properties. You can also define whether the property can be animatable. In addition, each of these properties has an update parameter that can be set to a callback function that is called whenever the property is changed.

def changeFunc(self, context):
    print("The value changed")

bpy.types.Object.testValue = bpy.props.FloatProperty(default=0, update=changeFunc)
Python
Example of running the prior code to call a function when the value changes in the Python Console

Vectors 

There are also vector properties that correspond to bool, float, and int. You can set the size of the vector from 1 to 32.

bpy.types.Object.vectorTest = bpy.props.FloatVectorProperty(size=3, default=(0,0,0))
Python

Enum Property

The Enum Property is useful for making a static list of items. For example, if you are making a UI panel, and you want to offer a dropdown where the user can pick an option. To create a Enum property:

bpy.types.Object.enumTest = bpy.props.EnumProperty(items=[('option1','test1','the first option'),('option2','test2','the second option')])
Python

The enum property that is created returns the string of the currently selected item.

If you want a dynamic list of items, you can set the items parameter to a callback function that returns a list of tuples.

def GetItems(self, context):
    if "Cube" in bpy.context.object.name:
        itemList = [('option1','cube','equal sides'),('option2','rectangle','non equal sides')]
    else:
        itemList = [('option3','triangle','not a cube'),('option4','hexagon','6 sides')]

    return itemList

bpy.types.Object.testEnum = bpy.props.EnumProperty(items=GetItems)
Python

Note that there are some potential challenges to using a callback described in the Blender Python Gotchas.

Property Group

The last two items we will talk about, Property Groups and Collections, are different from the other properties. The Property Group allows you to create a custom property that is composed of the underlying types. For example, you can create a group that includes a string name and a float value. To do this, we will create a subclass of PropertyGroup and then assign it to objects (bpy.types.Object).

class TestPropGroup(bpy.types.PropertyGroup):
    name: bpy.props.StringProperty(name="name", default="")
    value: bpy.props.IntProperty(name="value", default=0)

bpy.utils.register_class(TestPropGroup)
bpy.types.Object.test_prop = bpy.props.PointerProperty(type=TestPropGroup)
Python

To set the properties in the property group:

bpy.context.object.test_prop.name = "Marvin"
bpy.context.object.test_prop.value = 42
Python

And to access the properties:

print(bpy.context.object.test_prop.name)
print(bpy.context.object.test_prop.value)
Python

The property group is useful to keep properties organized. You can place all of your properties together. The property group is even more powerful when paired with a collection. With a collection, we can create a list of property group items.

Collection Property

The collection is an array or list of properties. To create a collection:

class MyFloatProp(bpy.types.PropertyGroup):
    name: bpy.props.StringProperty(default="")
    value: bpy.props.FloatProperty(default=0)
    
bpy.utils.register_class(MyFloatProp)
bpy.types.Object.my_settings = bpy.props.CollectionProperty(type=MyFloatProp)
Python

You can add and remove elements from the collection:

bpy.context.object.my_settings.add()
Python

This returns a reference to the item we just added. We can access through bpy.context.object.my_settings[0] or we could instead write:

newItem = bpy.context.object.my_settings.add()
Python

We can now set the new item with:

newItem.name = "first"
newItem.value = 42
Python

Inherited Properties

In the Blender Python API reference, the properties include sections on inherited properties. However, I struggled to get these to work. In particular, I wanted to access the list of items in EnumProperty. However, if I tried to use items inherited function, it did not work. It gave the following error:

Error from calling the inherited functions from the property directly.

I realized that the property is actually stored elsewhere. To access a property attached to an object, you need to use the following.

bpy.context.object.bl_rna.properties["PropertyName"]
Python

This will allow you to access the underlying inherited properties. For example, if we have the following enum property:

bpy.types.Object.testEnum = bpy.props.EnumProperty(items=[('option1','first',''),('option2','second','')])
Python

We can access the items with:

for item in bpy.context.object.bl_rna.properties["testEnum"].enum_items:
    print(item.name)
Python

Conclusion

This post provides an overview to Blender Python properties. With this foundation, we can add properties to operators or to datablocks to customize the operation of Blender.


If you enjoyed this post, consider subscribing to the newsletter where I share work-in-progress updates, upcoming tutorials, and the occasional behind-the-scenes look at what I’m building.

Visited 168 times, 1 visit(s) today

Leave a Reply

Your email address will not be published. Required fields are marked *