Is it possible to declare a function without arguments but then pass some arguments to that function without raising exception?
Asked Answered
L

5

19

In python is it possible to have the above code without raising an exception ?

def myfunc():
    pass

# TypeError myfunc() takes no arguments (1 given)
myfunc('param')

Usually in php in some circumstances I launch a function without parameters and then retrieve the parameters inside the function.

In practice I don't want to declare arguments in myfunc and then passing some arguments to it. The only one solution I found is myfunc(*arg). Are there any other methods ?

Letters answered 10/2, 2010 at 23:43 Comment(8)
Why is myfunc(*arg) not good enough?Seafowl
I'm guessing yuri doesn't (yet) know about *argFostoria
The implementation need myfunc to be a callback passed to another function which try call it in a list comprehension passing an arguments. So I don't have control over the callback implementation and the user can not-intentionally omit the *args (In the code I take care about this event)Letters
So that would be a bug and raise an exception and the user will remember to put *args. Why do you expect php syntax to work in python?Borderline
In that case, I too am not sure why you think *arg isn't good enough.Fostoria
@gnibbler @Fostoria I am tryng to evolve my knowledge from php to python so I compare the two behaviour and test the differences. I think the answer is "no you can't". Thanks for the explainationsLetters
Ah, in that case, one thing to get used to is in python it's generally considered good if there is one official way to do things.Fostoria
Does this answer your question? Variable number of parameters in callbackFullmouthed
C
19
>>> def myFunc(*args, **kwargs):
...   # This function accepts arbitary arguments:
...   # Keywords arguments are available in the kwargs dict;
...   # Regular arguments are in the args tuple.
...   # (This behaviour is dictated by the stars, not by
...   #  the name of the formal parameters.)
...   print args, kwargs
...
>>> myFunc()
() {}
>>> myFunc(2)
(2,) {}
>>> myFunc(2,5)
(2, 5) {}
>>> myFunc(b = 3)
() {'b': 3}
>>> import dis
>>> dis.dis(myFunc)
  1           0 LOAD_FAST                0 (args)
              3 PRINT_ITEM
              4 LOAD_FAST                1 (kwargs)
              7 PRINT_ITEM
              8 PRINT_NEWLINE
              9 LOAD_CONST               0 (None)
             12 RETURN_VALUE

And to actually answer the question: no, I do not believe there are other ways.

The main reason is pretty simple: C python is stack based. A function that doesn't require parameters will not have space allocated for it on the stack (myFunc, instead, has them in position 0 and 1). (see comments)

An additional point is, how would you access the parameters otherwise?

Collodion answered 10/2, 2010 at 23:50 Comment(2)
The stack comment is besides the point. Python is stack-based, but argument passing (and parsing) is not (arguments are always a single item on the stack, even when there are no arguments.) The reason Python doesn't ignore arguments is because it would hide errors.Selaginella
It's indeed quite possible I'm misreading what dis tells me :)Collodion
B
16

There are two ways to pass args in

By Position

>>> def myfunc(*args):
...  print "args", args
...
>>> myfunc("param")
args ('param',)

By Keyword

>>> def myfunc(**kw):
...  print "kw", kw
... 
>>> myfunc(param="param")
kw {'param': 'param'}

And you can use a combination of both

>>> def myfunc(*args, **kw):
...  print "args", args
...  print "kw", kw
... 
>>> myfunc("param")
args ('param',)
kw {}
>>>
>>> myfunc(param="param")
args ()
kw {'param': 'param'}
>>>
>>> myfunc("param", anotherparam="anotherparam")
args ('param',)
kw {'anotherparam': 'anotherparam'}
Borderline answered 10/2, 2010 at 23:48 Comment(0)
F
7

Sure can!

You can define variable length parameter lists like so:

def foo(*args):
    print len(args)

args is a tuple of your parameters so calling:

foo(1,2)

gives you the tuple (1, 2) inside your function.

Fostoria answered 10/2, 2010 at 23:47 Comment(1)
args will actually be a tuple.Amena
V
5

Here is a function decorator I wrote to do just that, along with an example of usage:

def IgnoreExtraArguments(f):
    import types
    c = f.func_code
    if c.co_flags & 0x04 or c.co_flags&0x08:
        raise ValueError('function already accepts optional arguments')
    newc = types.CodeType(c.co_argcount,
                   c.co_nlocals,
                   c.co_stacksize,
                   c.co_flags | 0x04 | 0x08,
                   c.co_code,
                   c.co_consts,
                   c.co_names,
                   c.co_varnames+('_ignore_args','_ignore_kwargs'),
                   c.co_filename,
                   c.co_name,
                   c.co_firstlineno,
                   c.co_lnotab,
                   c.co_freevars,
                   c.co_cellvars)
    f.func_code = newc
    return f

if __name__ == "__main__":
    def f(x,y):
        print x+y

    g = IgnoreExtraArguments(f)
    g(2,4)
    g(2,5,'banana')

    class C(object):
        @IgnoreExtraArguments
        def m(self,x,y):
            print x-y

    a=C()
    a.m(3,5)
    a.m(3,6,'apple')
Vegetal answered 17/5, 2014 at 13:5 Comment(1)
Haha, totally OTT. I love it. Never thought I'd see the decorator pattern in a python function. You should add the capability to show the docstring help to complete this piece of art, and add a python3 update.Best
T
1
> def vf(a=0):
>     aw = a + 5
>     print(aw)
> 
> vf() result: 5
> vf(5) result: 10
Tuition answered 9/11, 2022 at 13:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.