Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically creating classes with eval in python

I want to take an argument and create a class whose name is the argument itself. For example, I take 'Int' as an argument and create a class whose name is 'Int', that is my class would be like this.

class Int :
    def __init__(self,param) :
        self.value = 3

I am doing this by doing this.

def makeClass( x ) :

    return eval( 'class %s :\n    def __init__(self,param) :\n        self.type = 3'%(x,))

and then calling

myClass = makeClass('Int')
myInt = myClass(3)

I am getting a syntax error for this. Please help.

like image 979
noPE Avatar asked Dec 21 '22 11:12

noPE


2 Answers

eval is used for evaluating expressions, class is not an expression, it's a statment. Perhaps you want something like exec?

As a side note, what you're doing here could probably be done pretty easily with type, and then you sidestep all of the performance and security implications of using eval/exec.

def cls_init(self,param):
    self.type = 3

Int = type("Int",(object,),{'__init__':cls_init})
#           ^class name
#                ^class bases -- inherit from object.  It's a good idea :-)
#                           ^class dictionary.  This is where you add methods or class attributes.
like image 120
mgilson Avatar answered Jan 09 '23 17:01

mgilson


As requested, this works in Python 2.7 and Python 3.4, printing 3:

def makeClass(x):
    exec('class %s:\n\tdef __init__(self,v):\n\t\tself.value = v' % x)
    return eval('%s' % x)

myClass = makeClass('Int')
myInt = myClass(3)

print(myInt.value)

If you wish to add methods from the existing classes:

def makeClass(name):
    parent = name.lower()
    exec('class %s(%s):\n\tdef __init__(self,v):\n\t\tself.value = v' % (name, parent))
    return eval('%s' % name)

Int = makeClass('Int')
myInt = Int(3)

Str = makeClass('Str')
myStr = Str(3)

print(myInt.value, myInt == 3, myInt == 5)
print(myStr.value, myStr == '3', myStr == 3)

Output:

3 True False
3 True False

Less typing with side effects:

def makeClass(name):
    parent = name.lower()
    exec('global %s\nclass %s(%s):\n\tdef __init__(self,v):\n\t\tself.value = v' % (name, name, parent))

makeClass('Int')
myInt = Int(3)

makeClass('Str')
myStr = Str(3)

Mgilson's type answer is probably preferred, though.

like image 41
Cees Timmerman Avatar answered Jan 09 '23 16:01

Cees Timmerman