-1

I have the following simple example code:

def wrapper(foo, para1=1, *args):
    print("para1: "+ str(para1))
    print(foo(*args))

def foo1(x):
    return 2*x

wrapper(foo1, 2, 3)

where I define a function wrapper that has one parameter para1 with default value 1.

But in order to call the wrapper with function foo1 correctly, I have to set para1 all the time, because I have to pass the extra arguments to foo1. That means the default value para1=1 does not make any sense, as I have to define it all the time anyway.

Or is there some other way to define the functions so I can easilz make use of this default value without to have to define it all the time?

For example,

wrapper(foo1, *args=(3,))
wrapper(foo=foo1, args=(3,))

does not work ...

Use case example:

def wrapper(foo, timeout=10, *args):
    time0 = time.time()
    while time0 < time.time() + timeout:
        if foo(*args):
             return True
        time.sleep(1)
    raise SomeTimeout Exception
Alex
  • 41,580
  • 88
  • 260
  • 469
  • Possible duplicate of [Default arguments with \*args and \*\*kwargs](https://stackoverflow.com/questions/15301999/default-arguments-with-args-and-kwargs) – mkrieger1 Oct 18 '18 at 13:11
  • 1
    can't you put `para1` at the end of `wrapper` args? – Jean-François Fabre Oct 18 '18 at 13:12
  • No then I get a syntax error – Alex Oct 18 '18 at 13:13
  • @Jean-FrançoisFabre then calls like `wrapper(foo1, 2, 3)` will break – DeepSpace Oct 18 '18 at 13:13
  • I think that what you want is just impossible: too many constraints – Jean-François Fabre Oct 18 '18 at 13:17
  • That is correct. It is not being passed into foo1(). (e.g. a timeout parameter to check the completion of foo1() within some time etc.) – Alex Oct 18 '18 at 13:17
  • Is `foo1` always only taking a fixed number of param? perhaps you don't need to pass `*args` into `foo1()`? – r.ook Oct 18 '18 at 13:20
  • The number of parameters can change. Its not a fixed number of parameters in `*args`. – Alex Oct 18 '18 at 13:21
  • Given `wrapper(foo1, 2, 3)`, how do you propose the interpreter to know the difference between this as a call of `foo1(2, 3)` or `foo1(3)`? I don't think there's any meaningful distinction unless you use a keyword to identify the param that's specific to `wrapper()`. – r.ook Oct 18 '18 at 13:23
  • 1
    What is wrong again with `def wrapper(foo, *args, para1=1)`? – mkrieger1 Oct 18 '18 at 13:59
  • Which Python version are you using? Given your use of `print` it's Python 3? – mkrieger1 Oct 18 '18 at 13:59
  • @mkrieger1 I don't think there's anything wrong with it, unless OP is trying to stay away from keyword arguments (though it's stated as a possibility in the question title), in which case I just don't see a non-convoluted way of implementing unless there's a specific distinction between para1 and the `*args`. – r.ook Oct 18 '18 at 14:18

3 Answers3

0

You defined the foo1 function in a way that accepts a number, but you try to pass a tuple to it in the wrapper function. the following should work:

def wrapper(foo, para1=1, *args):
    print("para1: "+ str(para1))
    print(foo(*args))



def foo1(*x):
    return 2*x


wrapper(foo1, (2, 3))

in the definition of foo1 x changed to *x.

Super Hornet
  • 2,839
  • 5
  • 27
  • 55
  • @Idlehands, It works! Maybe, the error comes from somewhere else. – Super Hornet Oct 18 '18 at 13:59
  • It does not. Have you actually tested it? `SyntaxError: invalid syntax` is what gets raised. To be specific, `*args=...` is the source of the error. – r.ook Oct 18 '18 at 14:01
  • @Idlehands, Yes I have! I updated my answer with complete code – Super Hornet Oct 18 '18 at 14:05
  • With your latest edit, you're back to square one with OP. What if you wanted to call wrapper without the `para1`? `wrapper(foo1, 3)` does not work. The interpreter doesn't know the 2nd param does not exist. `3` is the 2nd param in this case. – r.ook Oct 18 '18 at 14:06
  • @Idlehands, alright. I got the question in a wrong way. I updated the answer. – Super Hornet Oct 18 '18 at 14:14
  • Please read the question carefully and test your answers. None of your edits have achieved what OP is looking for. – r.ook Oct 18 '18 at 14:20
0

Edit: Since you have now made it clear it is for Python 2, def wrapper(foo, *args, timeout=10) would give you a syntax error. So use the below method instead.

With just *args alone I don't think it's very feasible. If possible, try making use of **kwargs instead:

def wrapper(foo, *args, **kwargs):
    time0 = time.time()
    # define a default timeout period if not explicitly passed in by keyword
    timeout = kwargs.get('timeout') if 'timeout' in kwargs else 10
    while time0 < time.time() + timeout:
        if foo(*args):
            return True
        time.sleep(1)
    raise SomeTimeOut Exception

Every time you want to explicitly provide a timeout period, call it as such:

wrapper(foo, 1, 2, 3, timeout=60)

Test code:

def wrapper(foo, *args, **kwargs):
    timeout = kwargs.get('timeout') if 'timeout' in kwargs else 10
    print 'Timeout = {0}'.format(timeout)
    foo(*args)

def foo(*args):
    print 'Args = {0}'.format([a for a in args])

wrapper(foo, 1, 2, 3, timeout=20)

# Results
# Timeout = 20
# Args = [1, 2, 3]
r.ook
  • 13,466
  • 2
  • 22
  • 39
0

What about making it like this?

#/usr/bin/env python3

def f1(f, *args, **kwargs):
    if not 'b' in kwargs:
        kwargs['b'] = 1
    print('b =',kwargs['b'])
    f(args)

def fx(args):
    print(args)

f1(fx, 3, 4)
print()
f1(fx, 3, 4, b=2)

Output:

b = 1                                                                     
(3, 4)

b = 2                                                                     
(3, 4)
progmatico
  • 4,714
  • 1
  • 16
  • 27