Gadzooks34
Gadzooks34

Reputation: 1828

Dynamically instantiating objects

I'm attempting to instantiate an object from a string. Specifically, I'm trying to change this:

from node.mapper import Mapper
mapper = Mapper(file)
mapper.map(src, dst)

into something like this:

with open('C:.../node/mapper.py', 'r') as f:
    mapping_script = f.read()

eval(mapping_script)
mapper = Mapper(file)
mapper.map(src, dst)

The motivation for this seemingly bizarre task is to be able to store different versions of mapping scripts in a database and then retrieve/use them as needed (with emphasis on the polymorphism of the map() method).

The above does not work. For some reason, eval() throws SyntaxError: invalid syntax. I don't understand this since it's the same file that's being imported in the first case. Is there some reason why eval() cannot be used to define classes?

I should note that I am aware of the security concerns around eval(). I would love to hear of alternative approaches if there are any. The only other thing I can think of is to fetch the script, physically save it into the node package directory, and then import it, but that seems even crazier.

Upvotes: 2

Views: 116

Answers (1)

Mike Müller
Mike Müller

Reputation: 85442

You need to use exec:

exec(mapping_script)

eval() works only for expressions. exec() works for statements. A typical Python script contains statements.

For example:

code = """class Mapper: pass"""
exec(code)
mapper = Mapper()
print(mapper)

Output:

<__main__.Mapper object at 0x10ae326a0>

Make sure you either call exec() (Python 3, in Python 2 it is a statement) at the module level. When you call it in a function, you need to add globals(), for example exec(code, globals()), to make the objects available in the global scope and to the rest of the function as discussed here.

Upvotes: 1

Related Questions