3

我正在使用该cmd模块编写一个快速 python 脚本,该模块将允许用户输入文本命令,后跟基本 url 查询字符串格式的参数。提示将得到类似的回答

commandname foo=bar&baz=brack

使用 cmd,我似乎找不到要覆盖哪个方法来影响将参数line传递给所有方法的do_*方式。我想urlparse.parse_qs在这些值上运行,并且在每个do_*方法中逐行调用它似乎很笨拙。

precmd方法在拆分和解释之前获取整行,commandname因此这不适用于我的目的。我也不太熟悉如何在这样的类中放置装饰器,并且无法在不破坏范围的情况下将其拉下来。

基本上,cmd的 python 文档说如下

反复发出提示,接受输入,解析接收到的输入的初始前缀,然后分派给操作方法,将行的其余部分作为参数传递给它们。

我想创建一个方法,对“行的剩余部分”进行额外的处理,并将生成的字典作为line参数传递给成员函数,而不是在每个函数中解释它们。

谢谢!

4

1 回答 1

3

您可能会覆盖该onecmd()方法,如下面的快速示例所示。该onecmd()方法基本上是原始方法的副本,但在将参数传递给函数之前cmd.py添加了调用。urlparse.parse_qs()

import cmd
import urlparse

class myCmd(cmd.Cmd):
    def onecmd(self, line):
        """Mostly ripped from Python's cmd.py"""
        cmd, arg, line = self.parseline(line)
        arg = urlparse.parse_qs(arg) # <- added line
        if not line:
            return self.emptyline()
        if cmd is None:
            return self.default(line)
        self.lastcmd = line
        if cmd == '':
            return self.default(line)
        else:
            try:
                func = getattr(self, 'do_' + cmd)
            except AttributeError:
                return self.default(line)
            return func(arg)

    def do_foo(self, arg)
        print arg

my_cmd = myCmd()
my_cmd.cmdloop()

样本输出:

(Cmd) foo
{}
(Cmd) foo a b c
{}
(Cmd) foo a=b&c=d
{'a': ['b'], 'c': ['d']}

这是你想要达到的目标吗?

这是另一个潜在的解决方案,它使用类装饰器来修改 cmd.Cmd子类并基本上将装饰器函数应用于do_* 该类的所有方法:

import cmd
import urlparse
import types

# function decorator to add parse_qs to individual functions
def parse_qs_f(f):
    def f2(self, arg):
        return f(self, urlparse.parse_qs(arg))
    return f2

# class decorator to iterate over all attributes of a class and apply
# the parse_qs_f decorator to all do_* methods
def parse_qs(cls):
    for attr_name in dir(cls):
        attr = getattr(cls, attr_name)
        if attr_name.startswith('do_') and type(attr) == types.MethodType:
            setattr(cls, attr_name, parse_qs_f(attr))
    return cls

@parse_qs
class myCmd(cmd.Cmd):
    def do_foo(self, args):
        print args

my_cmd = myCmd()
my_cmd.cmdloop()

我很快将它拼凑在一起,它似乎按预期工作,但是,我愿意接受有关任何陷阱或如何改进此解决方案的建议。

于 2012-04-19T21:42:32.067 回答