Your first example is on the right track, but your descriptor is storing the data inside itself. There is only one descriptor instance PER CLASS, that’s why you’re getting the shared data. In a case like that you want will need to create some storage mechanism that’s not part of the descriptor to hold the reeal data.
Here’s two different examples for different situations:
- The data lives in an outside object. Here’ the class wraps a maya object so you get and set the property from there:
class XformProperty( object ):
def __init__( self, flag ):
self.Flag = flag
self._q_args = {'q':True, flag:True}
self._e_args = {flag: 0}
def __get__( self, obj, objtype ):
return cmds.xform( obj, **self._q_args )
def __set__( self, obj, value ):
self._e_args[self.Flag] = value
cmds.xform( obj.Object, **self._e_args )
class Xform( object ):
def __init__( self, obj ):
self.Object = cmds.ls( obj.Object, l=True )[0]
translation = XformProperty( 'translation' )
In that example, the Xform class holds a maya transform name. When you get or set .translation, it’s checking the stored object name and then calling cmds.xform. You see it uses the stored object name when called. This lets it work on different objects, since the differentiating factor is the obj.Object field.
- data lives in the class object, but you want to simplify the storage and avoid boilerplate (or do something else when the value is touched)
class LateBoundProperty(object):
def __init__(self, name, class_default="IGNORE"):
self._class_default_string = class_default
self._name = "_" + name
def __create_backstore(self, instance, owner=None):
if not hasattr(instance, self._name):
default = None
if owner and hasattr(owner, self._class_default_string):
default = copy.copy(getattr(owner, self._class_default_string))
setattr(instance, self._name, default)
def __get__(self, instance, owner):
self.__create_backstore(instance, owner)
return getattr(instance, self._name)
def __set__(self, instance, val):
self.__create_backstore(instance)
setattr(instance, self._name, val)
This is a property descriptor that’s useful for mixin classes that need to create instance properties but which won’t get called in the init of a class they are tacked onto. As you can see it actually adds a field with the same name as the property and a leading underscore to an object it’s attached to and then manages the per-object data there. It also specifes the name of class-level default that can be set if needed.
class Mixin(object):
example = LateBoundProperty('example', '_EX')
class Target (Mixin):
_EX = 99
print Target().example
# 99