Получить метод, завернутый в дескриптор с помощью getattr - PullRequest
1 голос
/ 16 февраля 2011

У меня есть следующий дескриптор, который сохраняет конфигурацию внутри моего класса после вызова метода, помеченного @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.

Ответы [ 2 ]

2 голосов
/ 16 февраля 2011

Я все еще не уверен на 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 - это вспомогательный декоратор, который делает обертку, имитирующую оригинальную функцию (то есть копирует имя функции, строку документации и тому подобное).).Это облегчит отладку, так как вы будете знать, откуда происходят исключения и т. Д.

1 голос
/ 16 февраля 2011

Прежде всего, извините за комментарий, моя ошибка, теперь ваш последний код не будет работать как вы, который (ваш метод больше не оформлен), потому что для понимания декоратора вы должны увидеть это:

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

эквивалентно:

class pbtools():

    def getip():
        (...)

    getip = saveconfig(getip)

и в вашем последнем случае saveconfig return 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

Надеюсь, это поможет:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...