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()
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
.