michaelmeyer
michaelmeyer

Reputation: 8205

Attach a method to a class while the class is being created

I've defined two classes as follows:

class ClassModel(object):
    pass

class FunctionModel(object):
    attr = None
    def __call__(self):
        return self.attr

The idea is to create several copy of ClassModel, each one containing zero or more methods inheriting from FunctionModel, which should have each one their own attributes.

I'm fine for creating children of ClassModel and FunctionModel. But I don't succeed to attach the two so that, when the children of ClassModel are instanciated, the function-like objects derived from FunctionModel which have been attached to them are recognized by Python as their methods.

See what happens

>>> func = type('func', (FunctionModel,), {'attr': 'someattr'})
>>> func_inst = func()
>>> func_inst
<__main__.func object at 0x968e4ac>
>>> Cls = type('Cls', (ClassModel,), {'func_inst': func_inst})
>>> cls_inst = Cls()
>>> cls_inst.func_inst
<__main__.func object at 0x968e4ac>

How can I go with this ?

Upvotes: 1

Views: 101

Answers (3)

jimifiki
jimifiki

Reputation: 5534

Consider using metaclasses, here an example:

class ClassModel(object):
    attr = None 

class FunctionModel(object):
    attr = None
    def __init__(self,aValue):
        self.attr = aValue
    def __call__(self, cls):
        return self.attr + cls.attr

def getFMClasses(aDictOfMethods): 
    class MM(type):
        def __new__(cls, name, bases, dct):     
            for aName in aDictOfMethods: 
                dct[aName] = classmethod(FunctionModel(aDictOfMethods[aName]))
            return super(MM, cls).__new__(cls, name, bases, dct)
        pass                                                    
    pass                                                        
    return MM                                                   

Once all that is defined, getting new classes is a child game...

class NewClass1(ClassModel):
    __metaclass__ = getFMClasses({'method1':3,'method2':5})
    attr = 2 

class NewClass2(ClassModel):
    __metaclass__ = getFMClasses({'method1':6,'DifferentMethod':2,'OneMore':0})
    attr = 3 

myObj = NewClass1()
print myObj.method1()
print myObj.method2()
myObj = NewClass2()
print myObj.method1()
print myObj.DifferentMethod()
print myObj.OneMore()

Upvotes: 2

michaelmeyer
michaelmeyer

Reputation: 8205

I finally figured out how to do this. Class methods are added after the new class object is created (which is not exactly what I wanted), but before it is actually instanciated. Name of methods can be changed dynamically thanks to setattr.

class ClassModel(object):
    number = None

class FunctionModel(object):
    number = None
    def __call__(myself, clsself):
        return myself.number + clsself.number

Define the class and add it attributes:

from types import MethodType

func1 = type('func1', (FunctionModel,), {'number': 3})
func2 = type('func2', (FunctionModel,), {'number': 5})
func1_inst = func1()
func2_inst = func2()

Cls = type('Cls', (ClassModel,), {'number': 10})
setattr(Cls, 'func1', MethodType(func1_inst, Cls))
setattr(Cls, 'func2', MethodType(func2_inst, Cls))

And instanciate it:

cls_inst = Cls()
cls_inst.func1()
# 13
cls_inst.func2()
# 15

Upvotes: 0

danodonovan
danodonovan

Reputation: 20341

I may be completely wrong here, but surely you just want FunctionModel to be the parent class of ClassModel ?

class FunctionModel(object):
    attr = None
    def __call__(self):
        return self.attr

class ClassModel(FunctionModel):
    pass

Now ClassModel will have all the attributes of FunctionModel but beware of over-riding stuff. When creating an __init__ method for ClassModel you can make sure you call FunctionModels __init__ too with a super()

class ClassModel(FunctionModel):

    def __init__(self, extra_args):
        super(ClassModel, self).__init__()

        self.extra_args = extra_args

More information on python classes and inheritance here.

Upvotes: 0

Related Questions