在Python中大量使用getattr是坏习惯吗?

11 投票
2 回答
8900 浏览
提问于 2025-04-15 23:10

我正在创建一个类似于命令行的环境。最开始,我处理用户输入的方法是用一个字典,把命令(字符串)映射到不同类的方法上,这样做是因为在Python中,函数可以像普通对象一样使用。

为了更灵活一些(主要是为了解析命令),我在考虑改变我的设置,使用getattr(command)来获取我需要的方法,然后在解析器的最后将参数传递给它。这个方法的另一个好处是,每次我添加新方法或命令时,不需要每次都更新我现在静态实现的命令字典。

我有两个问题。首先,getattr是否会有和eval一样的问题?其次,这样做会影响我的命令行效率吗?命令或方法的数量会有影响吗?目前我有大约30个命令,未来可能会增加到60个。

2 个回答

11

getattr和eval有一样的问题吗?

没有!使用eval()的代码维护起来非常麻烦,而且可能会有严重的安全隐患。而调用getattr(x, "foo")其实就是另一种写法,等同于x.foo

我的命令行效率会受到影响吗?

如果找不到命令,确实会稍微慢一点,但这个影响几乎感觉不到。只有在做大量数据测试,比如有几万个条目的时候,才可能注意到这个差别。

28

直接访问属性和使用 getattr() 之间的区别其实不大。你可以用 Python 的 dis 模块来查看这两种方法的字节码,看看它们的不同之处:

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

不过,听起来你正在开发一个命令行界面,这个界面和 Python 的 cmd 库非常相似。cmd 允许你创建一个可以执行命令的界面,它通过匹配命令名称来找到在 cmd.Cmd 对象上定义的函数,像这样:

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

你可以在文档中了解更多关于这个模块的信息,或者访问 http://www.doughellmann.com/PyMOTW/cmd/index.html

撰写回答