Is it bad practice to use python's getattr extensively?
Asked Answered
S

2

12

I'm creating a shell-like environment. My original method of handleing user input was to use a dictionary mapping commands (strings) to methods of various classes, making use of the fact that functions are first class objects in python.

For flexibility's sake (mostly for parsing commands), I'm thinking of changing my setup such that I'm using getattr(command), to grab the method I need and then passing arguments to it at the end of my parser. Another advantage of this approach is not having to update my (currently statically implemented) command dictionary every time I add a new method/command.

My question is two fold. First, does getattr have the same problems as eval? Second, will I be taking a hit to the efficiency of my shell? Does it matter how many methods/commands I have? I'm currently looking at 30 some commands, which could eventually double.

Sturtevant answered 26/5, 2010 at 0:21 Comment(2)
if you haven't looked at pyparsing pyparsing.wikispaces.com you really should, there is NO real reason to write your own parser in python for anything.Huron
Fuzzy, I'm pretty sure I can think of one, and it's what I'm doing it for: learning purposes. Before starting this current project I didn't understand the implications of functions being first class objects. I do appreciate the reference though. I'll look into it.Sturtevant
C
29

The difference between direct attribute access and using getattr() should be fairly negligible. You can tell the difference between the two versions' bytecodes by using Python's dis module to compare the two approaches:

>>> import dis
>>> dis.dis(lambda x: x.foo)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_ATTR                0 (foo)
              6 RETURN_VALUE        
>>> dis.dis(lambda x: getattr(x, 'foo'))
  1           0 LOAD_GLOBAL              0 (getattr)
              3 LOAD_FAST                0 (x)
              6 LOAD_CONST               0 ('foo')
              9 CALL_FUNCTION            2
             12 RETURN_VALUE  

It does, however, sound like you are developing a shell that is very similar to how the Python library cmd does command line shells. cmd lets you create shells that executes commands by matching the command name to a function defined on a cmd.Cmd object like so:

import cmd

class EchoCmd(cmd.Cmd):
    """Simple command processor example."""

    def do_echo(self, line):
        print line

    def do_EOF(self, line):
        return True

if __name__ == '__main__':
    EchoCmd().cmdloop()

You can read more about the module at either the documentation, or at http://www.doughellmann.com/PyMOTW/cmd/index.html

Cogan answered 26/5, 2010 at 2:7 Comment(1)
Thanks for this response. As in my comment above, I'm really writing this shell for learning purposes. In the future, if I actually need to write a shell for some production purpose, I'll be using cmd. I didn't know about dis though, thanks for the reference.Sturtevant
C
12

does getattr have the same problems as eval?

No -- code using eval() is terribly annoying to maintain, and can have serious security problems. Calling getattr(x, "foo") is just another way to write x.foo.

will I be taking a hit to the efficiency of my shell

It will be imperceptibly slower if the command isn't found, but not enough to matter. You'd only notice it if doing benchmarks, with tens of thousands of entries.

Colorable answered 26/5, 2010 at 0:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.