简体   繁体   中英

Procedurally created decorator functions

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?

You can dynamically add property s, 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. Ie 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))

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM