Decorating a function and adding functions that preserve the number of arguments

I would like to decorate a function using a template similar to this:

def deco(func):
    def wrap(*a,**kw):
        print "do something"
        return func(*a,**kw)
    return wrap

The problem is that if the decorated function has a prototype like this:

def function(a,b,c): return

When decorating, the prototype is destroyed by varargs, for example, the calling function (1,2,3,4) will not lead to an exception. Is this a way to avoid this? How to define a wrapping function with the same prototype as decorated (func)?

Is there something conceptually wrong?

EDIT

My perverted idea was to make it easier to “call the parent method” without changing the signature. Sort of

def __init__(self, something)
    super(ClassName, self).__init__(something)

at

@extended
def __init__(self, something):
    ...

I figured out if this is possible, and if that makes sense.

EDIT As Alex noted, the following code does not throw an exception:

function(1,2,3,4)
+3
source share
4

decorator , .

, , inspect.getargspec .

exec. , .

+3

, , " (1,2,3,4) ". :

>>> def deco(f):
...   def w(*a, **k):
...     print 'do something'
...     return f(*a, **k)
...   return w
... 
>>> def f(a, b, c): return
... 
>>> f(1, 2, 3, 4)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: f() takes exactly 3 arguments (4 given)
>>> decorated = deco(f)
>>> decorated(1, 2, 3, 4)
do something
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 4, in w
TypeError: f() takes exactly 3 arguments (4 given)

, , unecorated f ( print).

(name, docstring functools.wraps. , (to ) ( "" , , " " , , - ; -0).

, (, , ?), (, , , - ;-), .

+4

, , . , , :

import inspect, time
import functools

def decorator_wrapper(old_function, new_function):
    args, arglist, kw, default = inspect.getargspec(old_function)
    args = list(args)

    if arglist:
       args.append(arglist)

    if kw:
       args.append(kw)

    callstring = inspect.formatargspec(args, arglist, kw, default, formatvalue=lambda value: "")
    argstring = inspect.formatargspec(args, arglist, kw, default)[1:-1]

    unique_name = "_func" + str(int(time.time()))
    codestring = "lambda " + argstring + " : " + unique_name + callstring
    decorated_function = eval(codestring, {unique_name: new_function})

    return functools.wraps(old_function)(decorated_function)
+3

result=func(*a,**kw), TypeError " -".

def deco(func):
    def wrap(*a,**kw):
        result=func(*a,**kw)
        print "do something"
        return result
    return wrap

@deco
def function(a,b,c): return

function(1,2,3)
# do something
function(1,2,3,4)
# TypeError: function() takes exactly 3 arguments (4 given)
0

Source: https://habr.com/ru/post/1747617/


All Articles