使用getattr获取包含在描述符中的方法

时间:2011-02-16 17:58:00

标签: python descriptor

我有以下描述符,在调用注释为@saveconfig的方法后,将配置保存在我的类中:

class saveconfig(object):
    def __init__(self, f):
        self.f = f

    def __get__(self, instance, owner):
        def wrapper(*args):
            self.f(instance, *args)
            instance.cfg.write()
            instance.paramcfg.write()
        return wrapper

它的使用方式如下:

class pbtools():
    @saveconfig
    def getip(self, ip):
        (...)

工作正常。现在我想通过使用getattr获取装饰方法。但由于该方法由描述符包装,因此我只获得wrapper

pbt = pbtools()
# results in "<function wrapper at 0x23cced8>:"
method = getattr(pbt, "getip")

如何使用getattr访问包装的方法getip,以便能够通过它的名称来调用它? (当然我无法直接访问该方法,否则我不必这样做。)

补充说明:

从命令行调用脚本。我必须将命令行参数(字符串)映射到具有相同名称的方法以调用它。此外,我必须将comamndline中的任何其他参数映射到方法的参数,如下所示:

pbtools getip 192.168.178.123 #-> calls getip with parameter 192.168.178.123

由于我无法获得原始方法,我不知道它有多少参数来映射它们。我有几种方法可以像这样装饰,因为我想从pbtools-class中的方法中删除保存配置的交叉问题。

2 个答案:

答案 0 :(得分:2)

我仍然不能100%确定我完全理解你的问题。你说“因为我不能得到原始方法,我不知道它有多少参数来映射它们”,但你不需要访问原始方法来调用可变数量的参数(因为装饰器有*args)。你可以这样做:

import sys
cmd = sys.argv[1]
params = sys.argv[2:]

pbt = pbtools()

func = getattr(pbt, cmd)
func(*params)

您还可以简化装饰器。它实际上并不需要__get__机制。

import functools

def saveconfig(f):
    @functools.wraps(f)
    def wrapper(self, *args):
        f(self, *args)
        self.cfg.write()
        self.paramcfg.write()
    return wrapper

functools.wraps是一个帮助装饰器,它使包装器模仿原始函数(即它复制函数名,docstring和类似的东西)。它将使调试更容易,因为您将知道异常源自何处等。

答案 1 :(得分:1)

首先抱歉评论我的错误,现在你的最后一段代码不会像你那样工作(你的方法不再装饰),因为了解装饰师你必须看到这个:

class pbtools():
    @saveconfig
    def getip():
        (...)

相当于:

class pbtools():

    def getip():
        (...)

    getip = saveconfig(getip)

并且在您的最新案例中saveconfig返回self.f,我们的代码中的getip等于getip = saveconfig(getip) ,因此在这种情况下此代码:

 getip = getip

相当于:

class saveconfig(object):
    def __init__(self, f):
        self.f = f

    def __get__(self, instance, owner):
        def wrapper(*args):
            self.f(instance, *args)
            instance.cfg.write()
            instance.paramcfg.write()

        wrapper.func = self.f    # Create a new attribute and assign it to the wrapped func.
        return wrapper

所以基本上它什么都不做。

解决方法可以将包装函数保存在包装函数中,如下所示:

class pbtools():
    @saveconfig
    def getip():
        print "hi"

pbt = pbtools()
method = getattr(pbt, "getip")
print method.func
# <function getip at 0x2363410>
method.func()
# hi

现在你可以:

{{1}}

希望这有助于:)