Maghsood Salimi
Maghsood Salimi

Reputation: 25

why i face problem when i'm going to pass a dynamic function in Python

I'm going to pass a function dynamically to another class as shown below

    class simulator(object):
        def __init__(self, fn_):

            print(self.test(fn_))


        def test(self, fn):
            return  fn(self, 20)


    class t(object):

        s = 'def get_fitness(x, y):\n return x+y'

        exec(s)

        def fnGetFitness(self,genes):
            return get_fitness(genes, 10)

        simulator(fnGetFitness)



    t()

but i face error below:

    File "N:/Job/GA/mine/dyn.py", line 25, in fnGetFitness
          return get_fitness(genes, 10)

    NameError: name 'get_fitness' is not defined

i guess its something related to scopes but i can't handle it anyone on this?

EDIT :

this is a simpler code, showing the problem :

    class t(object):
        def __init__(self):
            exec('def get_fitness(x, y):\n return x+y')
            print(get_fitness(2,3))
    t()

Upvotes: 1

Views: 93

Answers (1)

Jean-François Fabre
Jean-François Fabre

Reputation: 140186

nothing to do with exec. What you're doing is equivalent (with safety removed) to:

class t(object):
    def get_fitness(x,y):
        return x+y

but your method definition is at class level, but not on the simulator class.

simulator(fnGetFitness) calls fnGetFitness out of t class context, so it doesn't know your new function.

That cannot work (also get_fitness should be decorated as @staticmethod because it doesn't have a self parameter)

What works is to define dynamically (or not) the function at global level so class can call it

s = 'def get_fitness(x, y):\n return x+y'
exec(s)

class t(object):
    def fnGetFitness(self,genes):
        return get_fitness(genes, 10)

    simulator(fnGetFitness)

t()

that fixed it, but honestly I'm puzzled about the purpose (already took me a while to figure out how to make something run from your code)

EDIT: a simpler and somehow different (and exec related) code has been posted in comments:

class t(object):
    def __init__(self):
        exec('def get_fitness(x, y):\n return x+y')
        print(get_fitness(2,3))
t()

this raises NameError: name 'get_fitness' is not defined

now this has to do with exec. When __init__ is parsed, get_fitness isn't known because the parser didn't see it as a local variable, even if at the time of execution, it is set in locals() dictionary by exec (related: why is 'ord' seen as an unassigned variable here?).

A workaround is to fetch the function in the local variables like this:

class t(object):
    def __init__(self):
        exec('def get_fitness(x, y):\n return x+y')
        print(locals()["get_fitness"](2,3))

t()

this works & prints 5.

Upvotes: 1

Related Questions