How to dynamicly define function and call the function?

F

FAN

I want to define some function in python script dynamicly and call
them later, but I get some problem. I have tried the following:

##################################
# code
##################################
class test:
def __init__(self):
exec("def dfunc(msg):\n\tprint msg\nprint 'exec def function'")
dfunc('Msg in init ...') # it work

def show(self, msg):
dfunc(msg) # doesn't work !
exec('dfunc(msg)') # doesn't work too!

d = test()
d.show('hello')
###################################
#output
##################################
exec def function
Msg in init ...
Traceback (most recent call last):
File "test.py", line 10, in ?
d.show('hello')
File "test.py", line 7, in show
dfunc(msg)
NameError: global name 'dfunc' is not defined
##################################

I think this maybe cause by the scope of function definition, for the
first call of 'dfunc' in __init__ work. So I tried to define the
function as a member function of class 'test', but this time even the
first call doesn't work:

##################################
# code
##################################
class test:
def __init__(self):
exec("def dfunc(self,msg):\n\tprint msg\nprint 'exec def function'")
self.dfunc('Msg in init ...')

def show(self, msg):
exec("self.dfunc(msg)")

d = test()
d.show('hello')
###################################
#output
##################################
exec def function
Traceback (most recent call last):
File "test.py", line 9, in ?
d = test()
File "test.py", line 4, in __init__
self.dfunc('Msg in init ...')
AttributeError: test instance has no attribute 'dfunc'
##################################

Is there any way I can solve this problem?

Regards

- FAN
 
L

Leif K-Brooks

FAN said:
class test:
def __init__(self):
exec("def dfunc(msg):\n\tprint msg\nprint 'exec def function'")
dfunc('Msg in init ...') # it work

def show(self, msg):
dfunc(msg) # doesn't work !
exec('dfunc(msg)') # doesn't work too!

class Test(object):
def __init__(self):
exec "def dfunc(msg):\n print msg"
dfunc('Hello from __init__.')
self.dfunc = dfunc

def show(self, msg):
self.dfunc(msg)


(Of course, this is assuming your real function is more complicated than
the one you've posted; if it isn't, you don't need to use exec to define
it.)
 
B

bruno modulix

FAN said:
I want to define some function in python script dynamicly and call
them later, but I get some problem. I have tried the following:

##################################
# code
##################################
class test:
def __init__(self):
exec("def dfunc(msg):\n\tprint msg\nprint 'exec def function'")
dfunc('Msg in init ...') # it work

def show(self, msg):
dfunc(msg) # doesn't work !
I think this maybe cause by the scope of function definition, for the
first call of 'dfunc' in __init__ work.

The exec statement syntax is:
"exec" expression ["in" expression ["," expression]]

http://www.python.org/doc/2.4.1/ref/exec.html

Without the optional part, the default is to execute the statement in
the current scope. As Python allows defining nested functions, the
dfunc() function is local to the the __init__() function and doesn't
exists in the class scope or the global scope.

class Test2(object):
def __init__(self):
exec "def dfunc(msg):\n\tprint msg\nprint 'exec def function'" \
in globals()
dfunc('Msg in init ...') # it work

def show(self, msg):
dfunc(msg)

d2 = Test2()
d2.show('hello')

But I would not advise you to use exec this way...
So I tried to define the
function as a member function of class 'test', but this time even the
first call doesn't work:

##################################
# code
##################################
class test:
def __init__(self):
exec("def dfunc(self,msg):\n\tprint msg\nprint 'exec def function'")
self.dfunc('Msg in init ...')

Here again, for the function to become a method of the class, it has to
be defined in the scope of the class - not in the scope of the
__init__() function:

class Test(object):
exec "def dfunc(self,msg):\n\tprint msg\nprint 'exec def function'"

def __init__(self):
self.dfunc('Msg in init ...')


def show(self, msg):
self.dfunc(msg)

d = Test()
d.show('hello')
Is there any way I can solve this problem?

The first question that comes to mind is "aren't you trying to solve the
wrong problem ?". If you tell us more about your real use case, we may
point you to others - possibly better - ways of solving it. I don't mean
that it's wrong to use the exec statement, but my experience is that
I've never had a use case for it in 5+ years of Python programming.
Everytime I thought I needed exec, it turned out that there was a much
better solution, usually involving callables, closures, properties,
descriptors, metaclasses, or any combination of...

Also, the fact that you seems to be at lost with Python's inner
mechanisms makes me think you probably don't know other - possibly
better - ways to solve your problem.

If what you need is to "parameterize" a function, closures and nested
functions may be a better solution. A silly exemple:

def makeadder(step):
def adder(num):
return step + num
return adder

add1 = makeadder(1)
add3 = makeadder(3)

add1(1)
=> 2
add1(2)
=> 3
add2(1)
=> 3
add2(2)
=> 4

Functions being first-class citizen in Python, it's easy to parameterize
a function with another:

import sys
def buildfun(funtest, funiftrue, funiffalse):
def built(arg):
if funtest(arg):
print "%s is true for %s" % (funtest, arg)
funiftrue("%s\n" % str(arg))
else:
print "%s is false for %s" % (funtest, arg)
funiffalse("%s\n" % str(arg))
return built

b = buildfun(lambda arg: arg == 42, sys.stdout.write, sys.stderr.write)
b(42)
b("toto")

Another possibility is to work with callable objects. A function in
Python is just an object (an instance of the function class), and any
object having a __call__() method is callable:

class Greeter(object):
def __init__(self,
name,
greeting="hello %(who)s, my name is %(name)s"):

""" greeting is supposed to be a format string
with %(name)s and %(who)s in it
"""
self.name = name
self.greeting = greeting

def __call__(self, who):
return self.greeting % {'name': self.name, 'who': who}

Yet another possibility is to go with metaclasses, but I won't give an
exemple here !-)


HTH
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top