dynamic construction of variables / function names

S

Sakcee

python provides a great way of dynamically creating fuctions calls and
class names from string

a function/class name can be stored as string and called/initilzed

e.g

def foo(a,b):
return a+b

def blah(c,d):
return c*d


list = ["foo", "blah"]

for func in list:
print func(2,4)

or similar items


what is the way if the names of functions are some modification e.g

def Newfoo(a,b):
return a+b

def Newblah(c,d):
return c*d

list = ["foo", "blah"]

for func in list:
print "New"+func(2,4)

or define a variable

"New"+list[0] = "First Funciton"


I think , print "New"+func(2,4) and "New"+list[0] = "First
Funciton"

will not work, either eval or exec should be used
is it correct way, is there a simple way, is this techniqe has a name?

thanks
 
L

limodou

python provides a great way of dynamically creating fuctions calls and
class names from string

a function/class name can be stored as string and called/initilzed

e.g

def foo(a,b):
return a+b

def blah(c,d):
return c*d


list = ["foo", "blah"]

for func in list:
print func(2,4)

or similar items


what is the way if the names of functions are some modification e.g

def Newfoo(a,b):
return a+b

def Newblah(c,d):
return c*d

list = ["foo", "blah"]

for func in list:
print "New"+func(2,4)

or define a variable

"New"+list[0] = "First Funciton"


I think , print "New"+func(2,4) and "New"+list[0] = "First
Funciton"

will not work, either eval or exec should be used
is it correct way, is there a simple way, is this techniqe has a name?

thanks

You could get the function object from globals(), for example:

for func in list:
f = globals().get("New"+func, None)
if f and callable(f):
print f(2, 4)
 
F

Felipe Almeida Lessa

Em Qua, 2006-03-29 às 22:44 -0800, Sakcee escreveu:
either eval or exec should be used
is it correct way, is there a simple way, is this techniqe has a name?

eval and exec are insecure. Try looking at globals():

$ python2.4
Python 2.4.3c1 (#2, Mar 29 2006, 08:34:35)
[GCC 4.0.3 (Debian 4.0.3-1)] on linux2
Type "help", "copyright", "credits" or "license" for more information..... return a+b
........ return c*d
....
list = ["foo", "blah"]
for func in list:
.... print globals()["New"+func](2, 4)
....
6
8.... print globals()
{'Newblah': <function Newblah at 0xb7d3df44>,
'__builtins__': <module '__builtin__' (built-in)>,
'Newfoo': <function Newfoo at 0xb7d3df0c>,
'list': ['foo', 'blah'],
'func': 'blah',
'__name__': '__main__',
'__doc__': None}
print globals()["New"+func]
print globals()["New"+func](2, 4) 8
# HTH,
....
 
D

Duncan Booth

Sakcee said:
python provides a great way of dynamically creating fuctions calls and
class names from string

a function/class name can be stored as string and called/initilzed

e.g

def foo(a,b):
return a+b

def blah(c,d):
return c*d


list = ["foo", "blah"]

for func in list:
print func(2,4)

or similar items

No, that doesn't work. To convert a string to a function name you have to
look it up in a suitable namespace, or store a list of functions instead of
a list of strings. So something like this would work:

lst = [foo, blah]

for func in lst:
print func(2,4)

what is the way if the names of functions are some modification e.g

def Newfoo(a,b):
return a+b

def Newblah(c,d):
return c*d

list = ["foo", "blah"]

for func in list:
print "New"+func(2,4)

or define a variable

"New"+list[0] = "First Funciton"


I think , print "New"+func(2,4) and "New"+list[0] = "First
Funciton"

will not work, either eval or exec should be used
is it correct way, is there a simple way, is this techniqe has a name?
One common way is to group the functions you want callable together in a
class and then use getattr to access them.

class Commands:
def Newfoo(self, a,b):
return a+b

def Newblah(self, c,d):
return c*d

def call(self, fname, *args. **kw):
fn = getattr(self, "New"+fname)
return fn(*args, **kw)

cmds = Commands()
lst = ["foo", "blah"]
for func in lst:
print cmds.call(func, 2, 4)
 
S

Steven D'Aprano

Sakcee said:
python provides a great way of dynamically creating fuctions calls and
class names from string

a function/class name can be stored as string and called/initilzed

e.g

def foo(a,b):
return a+b

def blah(c,d):
return c*d


list = ["foo", "blah"]

for func in list:
print func(2,4)

or similar items

Have you actually tried to do this? It doesn't work:

Traceback (most recent call last):
File "<stdin>", line 2, in ?
TypeError: object of type 'string' is not callable

(Also, it is poor practice to shadow the built-in list
as you have.)

You are attempting to call "foo"(2, 4). Strings are not
callable.

Two ways to actually do what you are trying to do is
with eval and exec:
5

but be aware of the possible security implications of
eval and exec.

If you are calling instance methods, you can use getattr:
.... def foo(self, x,y):
.... return x+y
....5

But the best way is, if possible, avoid this altogether
and remember that functions are first-class objects in
Python. Instead of doing this:

L = ["foo", "bar"]
for func in L:
print eval(func + "(2, 3)")

do this:

L = [foo, bar] # list containing function objects
for func in L:
print func(2, 3)

what is the way if the names of functions are some modification e.g

As far as I know, the only ways are: use eval or exec,
or look in locals and/or globals:
.... func(2, 3)
....
5

You can use globals() instead of locals(), but there
may be issues with scoping rules that I can't think of.

Personally, I think the best way is: find another way
to solve your problem.

is it correct way, is there a simple way, is this techniqe has a name?

I'm told that some people call this "dynamic
programming", but personally I call it "difficult to
maintain, difficult to debug programming".

(Before people get all cranky at me, I'm aware that it
isn't *always* the Wrong Way to solve problems, but it
is a technique which is subject to abuse and can often
be avoided by using function objects instead of
function names.)
 
B

bruno at modulix

Steven said:
(snip)

Personally, I think the best way is: find another way to solve your
problem.

See Duncan's post for a pretty clean and pythonic solution. Another one
that may be more explicit and avoid messing with locals() or globals() is:
I'm told that some people call this "dynamic programming",

In some other languages, it could be called 'metaprogramming', but this
is such a common idiom in Python that I'd just call this "programming" !-)
but
personally I call it "difficult to maintain, difficult to debug
programming".

Oh yes ? Why so ? I've used such patterns hundreds of time, and it has
never been a problem so far.

Dynamically selecting the function to call given a name (as string) is
is a well-known programming pattern. I learned this in C, using a
hashtable to store names/function pointer pairs. And that's mostly what
the proposed solutions (the one based on globals() or locals() as well
as Duncan's class-based one) do - the main difference being that Python
offers the hashtable for free !-)

nb : I agree that the use of the global or local namespaces may not be
the best thing to do - better to use (any variant of) Duncan's solution
IMHO.
(Before people get all cranky at me, I'm aware that it isn't *always*
the Wrong Way to solve problems, but it is a technique which is subject
to abuse and can often be avoided by using function objects instead of
function names.)

When you get the function name as user input, you cannot directly access
the function object.

And anyway, what do you think Python do when you call a function ?
Python namespaces *are* hash tables mapping symbols names (as string) to
objects (as pointers). I don't see much difference here.

(nb 2 : I agree that it is of course better to avoid 'manual' namespace
lookup whenever possible)
 

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,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top