# Is it possible to access an array in a custom property in a driver?

In a new project I've add a custom property to the default cube:

bpy.data.objects["Cube"]["positions"] = [4,3,2,1]


Is it possible to access this array from a driver, so that on every frame a different value is used?

If I add a driver it is possible to access a value from a fixed position:

But I'm not able to use frame to specify the index, Blender complains about the syntax:

I've also tried to use a frame handler to set a new property with the value to be used with the following Python script:

import bpy

def frame_handler(scene):
currentposition = bpy.data.objects["Cube"]["positions"][scene.frame_current % 4]
bpy.data.objects["Cube"]["currentposition"] = currentposition
print(currentposition)

bpy.app.handlers.frame_change_pre.clear()
bpy.app.handlers.frame_change_pre.append(frame_handler)


The code is executed every time the frame position is changed and the value is set to the custom property successfully. I'm also able to use this value in a driver - but when the value is changed the driver isn't :-( It looks like this is a bug: https://developer.blender.org/T66392

Is there some other way to solve this? I could work around these limitations but changing objects directly in my frame handler, but I'm would prefer to use a driver.

I've using Blender 2.80 RC3.

Use self.

Assuming the driver is on the same object as property

Have set a custom property on the object

>>> C.object["xxxx"] = [4, 3, 2, 1]
>>>


Scene current frame is known to the driver namespace as "frame", and can be used in expression without setting up a scene.frame_current driver variable for it.

Set use self of the driver to true, and self is the driven object in expression.

self["xxxx"][int(frame) % 4]


Driver variables by default are floats, hence the need to typecast frame

Getting Fancy

Can add pretty much anything to the driver namespace.

A simple wrapper class with a move method using the "xxxx" custom property if defined else use a default.

import bpy

class Mover:
def move(self, frame):
l = self.ob.get("xxxx", [0])
#print("debug...", ob.name, frame)
return l[int(frame % (len(l)))]

def __init__(self, ob):
self.ob = ob

bpy.app.driver_namespace["Mover"] = Mover


Can now add the driver to any object

Mover(self).move(frame)


or since frame is in namespace could grab its value, with a default juuuuust in case

frame = int(bpy.app.driver_namespace.get("frame", 0))


and the driver can become

Mover(self).move()


The possibilities are endless.

Note when using self in drivers the slow expression warning is reported, for what are the simplest of expressions.

Use self and the slow python expression

• So int(frame) instead of frame basically solved it. Dynamically typed languages tricks me all the time…
– PEK
Jul 27 '19 at 18:01
• The solution with the Mover class is clever. But to get it to work I needed to enable Auto Run Python Scripts in the setting.
– PEK
Jul 27 '19 at 18:01
• Cheers, forget about that setting. Assigning an instanced class to namespace, instead of a class and instancing like in example, provides a handy way to keep tabs on driven objects and there data. Jul 27 '19 at 18:17

You can do it with two variables in the driver:

• One to get current frame from the scene properties (f)

• One to get the positions array of the cube (var)

Then the driver formula can be var[f%4].

Note that if the expression fails once for some reasons, you'll need to click on "update dependencies" again.

• Thanks, this work almost perfectly :-). For some reason Blender doesn’t show the animation properly if I open your file and press the Play-button. But if I step one frame at the time or rendering the animation if works fine. However, if I change the expression to var[int(frame)%4] everything is fine :-)
– PEK
Jul 27 '19 at 17:09
• @batFinger answer is better and more complete anyway ; ) Jul 27 '19 at 17:11