I'm working on a library for a 3D application that wraps the application's functionality into a set of Python classes, as well as adding additional functionality that the application doesn't have.
I have a set of properties in my base class to add attributes to a node using the existing API, but I'd like a more elegant way of adding attributes dynamically. I currently have this code (which probably won't make much sense without familiarity with the 3D application) but the important bit is the
# Add block properties
and
# PROPERTIES
code.
class Block(pyunify.Transform):
def __init__(self, name = "Character"):
pyunify.Transform.__init__(self, name)
self.LockTransform()
class Spine(Block):
def __init__(self, name = "Character", numberOfJoints=6):
Block.__init__(self, name+"_spine")
# Add block properties
self.AddAttr("numberOfJoints", "long")
self.SetAttr("numberOfJoints", numberOfJoints)
# Create block template
self.Template()
# PROPERTIES
@property
def numberOfJoints(self):
return self.GetAttr("numberOfJoints")
@numberOfJoints.setter
def numberOfJoints(self, num):
self.SetAttr("numberOfJoints", num)
So I could foresee additional classes having a lot more properties, and the way I have it now, for every property I have to add it in _init__
self.AddAttr("numberOfJoints", "long")
self.SetAttr("numberOfJoints", numberOfJoints)
and then I have to add 2 additional functions in my class, a getter and setter, for that property so that I can call it within my class as self.numberOfJoints and it will interact with the class itself as well as setting the correct attributes on the accompanying node in the 3D application.
@property
def numberOfJoints(self):
return self.GetAttr("numberOfJoints")
@numberOfJoints.setter
def numberOfJoints(self, num):
self.SetAttr("numberOfJoints", num)
The only difference with the additional property functions will be the name, so I was wondering if there was a way I could create an AddProperty function in my base Block class so that I could just do this in my _init__ function:
self.AddProperty("numberOfJoints", "long")
self.numberOfJoints = 5
and it will dynamically create the getter and setter functions in addition to running the current _init__ line of
self.AddAttr("numberOfJoints", "long")
Any help would be appreciated!
Thanks!
If you want to do something that looks like property access, but under the performs a function, you want a descriptor. A descriptor is an object that looks like a property but intercepts get and set calls and lets you run whatever code you need. Here's a stackoverflow question with an example that uses descriptors to change an object's translation using descriptors:
https://stackoverflow.com/a/22292961/1936075
You could use the same trick to create, get and set custom attributes in a more readable, less cmds-heavy fashion.
More code here.