Question

My goal is to create a function that will procedurally generate a series of other functions within a class from serialized data. This is easy enough using dict , but... i would like for each function to be initialized with the @property decorator (or a similar custom decorator) so that i can call these functions like attributes

Basically, I would like to do something like the following:

class myClass(object):
    def __init__(self):
        self.makeFuncs(['edgar','allan','poe'])

    def makeFuncs(self, data):
        for item in data:
            self.__dict__[item] = '[%s] <--- is_the_data' % item 

myInstance = myClass()
print myInstance.poe
#'[poe] <--- is_the_data'

Got any Ideas?

Was it helpful?

Solution

You can dynamically add propertys, but properties are added to the class object, not the instance.

Here's an example:

def make_prop(cls, p):
    def f(self):
        print 'IN %s' % p
        return '[%s]' % p
    return f    

class myClass(object):
  pass

# add the properties
for p in ('edgar','allan','poe'):
    setattr(myClass, p, property(make_prop(myClass, p)))

y = myClass()
print y.a
print y.b

Prints:

IN allan
[allan]
IN poe
[poe]

Also, it is essential to use make_prop to create the function object, instead of creating them directly inside the for loop, due to python's lexical scoping. I.e. this won't work as expected:

# add the properties
for p in ('edgar','allan','poe'):
    def f(self):
        print 'IN %s' % p
        return '[%s]' % p
    setattr(myClass, p, property(f))

OTHER TIPS

Here is the answer I came to for procedurally adding properties to a custom shader class in maya.

Thx @shx2 !

import maya.cmds as mc
import sushi.maya.node.dependNode as dep

class Shader(dep.DependNode):
    def __init__(self, *args, **kwargs):
        super(Shader, self).__init__(*args, **kwargs)
        makeProps(self.__class__, ['color','transparency','ambientColor','incandescence','diffuse','translucence','translucenceDepth','translucenceFocus'])

def createShaderProperties(attrName):
    def getterProp(self):
        return mc.getAttr('%s.%s' % (self.name, attrName))[0]
    def setterProp(self, value):
        mc.setAttr('%s.%s' % (self.name, attrName), *value, type = 'double3')
    return (getterProp, setterProp)

def makeProps(cls, data):
    for dat in data:
        getterProp, setterProp = createShaderProperties(dat)
        setattr(cls, dat, property(getterProp))
        setattr(cls, dat, property.setter(cls.__dict__[dat],setterProp))

Your current idea won't work because property objects need to be in the class in order to work (they are descriptors). Since your list of functions is specific to each instance, that won't be possible.

However, you can make the general idea work using __getattr__. Here's an implementation that I think does what you want given a dictionary mapping from names to functions:

class MyClass(object):
    def __init__(self, func_dict):
        self.func_dict = func_dict

    def __getattr__(self, name):
        if name in self.func_dict:
            return self.func_dict[name]()     # call the function

        raise AttributeError("{} object has no attribute named {}"
                             .format(self.__class__.__name__, name)) # or raise an error
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top