dynamic construction of variables / function names

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Sakcee

    #1

    dynamic construction of variables / function names

    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

  • limodou

    #2
    Re: dynamic construction of variables / function names

    On 29 Mar 2006 22:44:24 -0800, Sakcee <sakcee@gmail.c om> wrote:[color=blue]
    > 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
    >[/color]

    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)

    --
    I like python!
    My Blog: http://www.donews.net/limodou
    My Site: http://www.djangocn.org
    NewEdit Maillist: http://groups.google.com/group/NewEdit

    Comment

    • Felipe Almeida Lessa

      #3
      Re: dynamic construction of variables / function names

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

      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.[color=blue][color=green][color=darkred]
      >>> def Newfoo(a, b):[/color][/color][/color]
      .... return a+b
      ....[color=blue][color=green][color=darkred]
      >>> def Newblah(c, d):[/color][/color][/color]
      .... return c*d
      ....[color=blue][color=green][color=darkred]
      >>> list = ["foo", "blah"]
      >>> for func in list:[/color][/color][/color]
      .... print globals()["New"+func](2, 4)
      ....
      6
      8[color=blue][color=green][color=darkred]
      >>> # That was a bit confusing, let see in parts[/color][/color][/color]
      .... 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}[color=blue][color=green][color=darkred]
      >>> print globals()["New"+func][/color][/color][/color]
      <function Newblah at 0xb7d3df44>[color=blue][color=green][color=darkred]
      >>> print globals()["New"+func](2, 4)[/color][/color][/color]
      8[color=blue][color=green][color=darkred]
      >>> # HTH,[/color][/color][/color]
      ....

      --
      Felipe.

      Comment

      • Duncan Booth

        #4
        Re: dynamic construction of variables / function names

        Sakcee wrote:
        [color=blue]
        > 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[/color]

        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)

        [color=blue]
        >
        >
        > 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?
        >[/color]
        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)

        Comment

        • Steven D'Aprano

          #5
          Re: dynamic construction of variables / function names

          Sakcee wrote:
          [color=blue]
          > 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[/color]

          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:
          [color=blue][color=green][color=darkred]
          >>> eval("foo(2, 3)")[/color][/color][/color]
          5[color=blue][color=green][color=darkred]
          >>> exec("print foo(2, 3)")[/color][/color][/color]
          5

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

          If you are calling instance methods, you can use getattr:
          [color=blue][color=green][color=darkred]
          >>> class Foo:[/color][/color][/color]
          .... def foo(self, x,y):
          .... return x+y
          ....[color=blue][color=green][color=darkred]
          >>> getattr(Foo(), "foo")(2, 3)[/color][/color][/color]
          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)

          [color=blue]
          > what is the way if the names of functions are some modification e.g[/color]

          As far as I know, the only ways are: use eval or exec,
          or look in locals and/or globals:
          [color=blue][color=green][color=darkred]
          >>> func = locals().get("f " + "oo", None)
          >>> if callable(func):[/color][/color][/color]
          .... 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.

          [color=blue]
          > is it correct way, is there a simple way, is this techniqe has a name?[/color]

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


          --
          Steven.

          Comment

          • bruno at modulix

            #6
            Re: dynamic construction of variables / function names

            Steven D'Aprano wrote:[color=blue]
            > Sakcee wrote:
            >[color=green]
            >> python provides a great way of dynamically creating fuctions calls and
            >> class names from string
            >>[/color][/color]
            (snip)
            [color=blue]
            > Personally, I think the best way is: find another way to solve your
            > problem.
            >[/color]

            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:
            [color=blue][color=green]
            >> is it correct way, is there a simple way, is this techniqe has a name?[/color]
            >
            >
            > I'm told that some people call this "dynamic programming",[/color]

            In some other languages, it could be called 'metaprogrammin g', but this
            is such a common idiom in Python that I'd just call this "programmin g" !-)
            [color=blue]
            > but
            > personally I call it "difficult to maintain, difficult to debug
            > programming".[/color]

            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.
            [color=blue]
            > (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.)[/color]

            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)



            --
            bruno desthuilliers
            python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
            p in 'onurb@xiludom. gro'.split('@')])"

            Comment

            Working...