Можно ли изменить возвращаемое значение функции без определения новой функции в Python?

def foo(a, b, c = 0):
    return a+b

У меня есть десятки функций, таких как 'foo', которые имеют разные номера аргументов и имена. Есть ли общий способ, которым я могу получить возвращаемые значения этих функций и выполнить с ними только одну дополнительную операцию, такую ​​как pformat?

Да, я могу просто сгенерировать новую функцию, подобную следующей:

func = ...  # func can be got using getattr by name
def wrapper(*arg, **kw):
    data = func(*arg, **kw)
    return pprint.pformat(data)
return wrapper

Но тогда новая функция "обертка" отличается от старой "func", например, в номере аргумента "обертка" имеет только 2 аргумента - "arg" и "kw", но "func" может иметь много аргументов, как "а", "б", "с".

Я просто хочу поиграть с возвращаемым значением, все остальное должно оставаться на месте, это возможно?

Спасибо!

Обновление Наконец, эта проблема была решена с помощью модуля декоратора и следующего патча:

--- /home/jaime/cache/decorator-3.2.0/src/decorator.py  2010-05-22 23:53:46.000000000 +0800
+++ decorator.py    2010-10-28 14:55:11.511140589 +0800
@@ -66,9 +66,12 @@
             self.name = '_lambda_' 
             self.doc = func.__doc__
             self.module = func.__module__
-            if inspect.isfunction(func):
+            if inspect.isfunction(func) or inspect.ismethod(func):
                 argspec = inspect.getargspec(func)
                 self.args, self.varargs, self.keywords, self.defaults = argspec
+                if inspect.ismethod(func):
+                    self.args = self.args[1:] # Remove the useless 'self' arg
+                    argspec = inspect.ArgSpec(self.args, self.varargs, self.keywords, self.defaults)
                 for i, arg in enumerate(self.args):
                     setattr(self, 'arg%d' % i, arg)
                 self.signature = inspect.formatargspec(

Этот патч позволяет вам декорировать ограниченные методы, он просто отбрасывает первый аргумент 'self', использование decorator.decorator остается прежним, никаких плохих эффектов сейчас не обнаружено.

пример кода:

def __getattr__(self, attr):
    def pformat_wrapper(f, *args, **kw):
        data = f(*args, **kw)
        return pprint.pformat(data, indent = 4)

    method = getattr(self.ncapi, attr)
    return decorator(pformat_wrapper, method) # Signature preserving decorating





jaime@westeros:~/bay/dragon.testing/tests$ python
Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import decorator
>>> class A:
...   def f(self):
...       pass
... 
>>> a = A()
>>> a.f
<bound method A.f of <__main__.A instance at 0xb774a20c>>
>>> def hello(f, *args, **kw):
...     print 'hello'
...     return f(*args, **kw)
... 
>>> f1 = decorator.decorator(hello, a.f)
>>> f1()
hello
>>>

3 ответа

Решение

О вашей проблеме:

"Но тогда новая функция" обертка "отличается от старой" func ", например, >> в номере аргумента" обертка "имеет только 2 аргумента -" arg "и" kw ", но" func "может иметь много >> аргументов, таких как 'a', 'b', 'c'."

Вы можете использовать модуль декоратора, который позволяет создавать сохраняющие подпись декораторы.

Декораторы.

from functools import wraps
def pformat_this( someFunc ):
    @wraps( someFunc )
    def wrapper(*arg, **kw):
        data = someFunc(*arg, **kw)
        return pprint.pformat(data)
    return wrapper


@pformat_this
def foo(a, b, c = 0):
    return a+b

Декораторы по сути такие же, как и те, которые вы не хотите.

Становясь любопытным, я изучил это для python 2.7 и обнаружил, что существует множество мета-информации, доступной для пользовательских функций в разделе Типы вызываемых -> Пользовательские функции. К сожалению, в возвращаемом значении ничего нет.

Существует также внутренний тип, к которому вы можете получить доступ через функцию, объект кода, на той же странице, в разделе Внутренние типы -> Объекты кода. Несмотря на то, что эти внутренние типы по существу не содержат никаких обещаний относительно стабильности API, кажется, что там нет ничего доступного для записи в отношении возвращаемого значения.

У меня такое ощущение, что если бы вы могли что-то сделать напрямую, это было бы здесь. Надеюсь, кому-то повезет больше.

Другие вопросы по тегам