1

我有以下描述符,它在@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")

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

补充说明:

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

pbtools getip 192.168.178.123 #-> calls getip with parameter 192.168.178.123

由于我无法获得原始方法,因此我不知道映射它们需要多少参数。我有几个这样装饰的方法,因为我想将保存配置的横切关注点移出 pbtools 类中的方法。

4

2 回答 2

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是一个帮助装饰器,它使包装器模仿原始函数(即它复制函数名称、文档字符串和类似的东西)。这将使调试更容易,因为您将知道异常的来源等。

于 2011-02-16T18:41:32.127 回答
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

希望这可以帮助:)

于 2011-02-16T18:30:11.590 回答