0

I have a generic class that I add dynamic properties to, and I want to add methods dynamically to instances, as certain instances will have different methods, but they need to access these dynamic properties.

How do I do this?

class GenericComponent:
    def __init__(self, ID):
        self.ID = ID

    @classmethod
    def addMethod(cls, func):
        return setattr(cls, func.__name__, types.MethodType(func, cls))

In my logic, as I build up these generic components I have something like this, so that for different instances I will have the same method name, but the logic inside it is different.

            if t==0:
                def toString(target):
                   print "toString: ", target
                   attrs = vars(target)
                   print ', '.join("%s: %s" % item for item in attrs.items())              
                obj = GenericComponent(ID)
                obj.ID = ID
                obj.name = "some random name"
                obj.addMethod(toString)
                obj.toString()

Unfortunately when I call obj.toString() it won't see obj.name

James Black
  • 41,583
  • 10
  • 86
  • 166

1 Answers1

1

You've made addMethod a class method. Python class methods can be called on an instance, as you do here with obj.addMethod(toString), but in that case the instance is used only to get its class; the first argument passed to addMethod is the class of obj.

Your addMethod call then makes the function passed as its second argument (in this example, toString) a bound method of the class. The instruction obj.toString() then first searches for the toString attribute of obj; that lookup process finds an attribute of the class that's also callable. But what you invoke then is not a bound method of the instance, but a bound method of the class. The method is then called with the class as the value of target and so it prints the attributes of the class, not those of the instance.

I'm not sure what exactly you're trying to achieve, but perhaps this is closer to what you want:

class GenericComponent:
    def __init__(self, ID):
        self.ID = ID
    def addMethod(self, func):
        return setattr(self, func.__name__, types.MethodType(func, self))

def toString(target):
    print "toString: ", target
    attrs = vars(target)
    print ', '.join("%s: %s" % item for item in attrs.items())
ID = 'some ID'
obj = GenericComponent(ID)
obj.name = "some random name"
obj.addMethod(toString)
obj.toString()
Alp
  • 2,766
  • 18
  • 13
  • I will try that in the morning. Thank you. A co-worker suggested that I may want to use obj.getattr("name") instead of obj.name, and that may work better. Basically I am working on a project where we don't know how we will solve the problem, and if I use defined classes instead of being so dynamic then we may be locked into a particular design. By being very dynamic I am not locked into any design. – James Black Jun 14 '13 at 01:36