Drivers act as an update function and are calculated in every frame of the animation.
Suppose you have a Custom Property
obj["prop"] that you need to control frame by frame, and a function
To set it up, you first need to add a simple line in your py code:
def pyFunction(self, targetName):
obj = bpy.data.objcts[targetName]
#Your code here
return x #where x is the value you want the driver, and therefore your ["prop"], to have
#this line lets Blender know that the pyFunction can be used in driver expressions
bpy.app.driver_namespace["pyFunction"] = pyFunction
then you can create a driver on the
["prop"] property, and write in the expression field
pyFunction(self, targetName), or whatever your variables are.
Note that all variables in that function must be initialized in the driver itself, so for "self" you need to tick the "Use self" checkbox, and for the others you need to create variables with the driver GUI (as a tip, if you want to put an object as a variable, create a single property variable in the driver and write "name" in the data path field, then in your pyFunction remember to get the object from the name, as I did in the code snippet before).
In alternative, you can create the driver on another property or object (like a hidden null). If you set it up this way, it doesn't matter what you put in the
return of the pyFunction (it only controls the driver's value), but you need to change the property in the function, something like:
target = bpy.data.objects[targetName]
control = bpy.data.objects[controlName]
#links the Custom Property to, for example, an object's location, however this can be any number you want
target["prop"] = control.location.x
#the return is not mandatory here, the driver will just have the value 0
In any case, the driver calculates the pyFunction every single frame as an update function, and execute the pyFunction's commands every frame