Defining function in Python accepts (x, *args), but not (*args, x). Why? - python

I have recently begun teaching myself Python and I have an inquiry regarding defining functions. I read about the *args and **args possibilites in functions and decided to try them out. I tried to make a very simple calculator by trying to make this function in IDLE:
def test(*args, tool):
total = 0
if(tool == '+' or tool == 'plus'):
for a in args:
total += a
return total
However, when I got passed the first line, Python threw this error at me:
SyntaxError: invalid syntax
At first, I didn't know what I did wrong, so I tried to type() them both and realized that *args is a tuple and **args is a dictionary. So I understood how Python would be confused when trying to convert a string of letters into a tuple and then finding what might be the tool part of the code.
However, when I switched place on the *args and tool: def test(tool, *args), I wasn't met with any errors at all and the code ran as expected (strangely, without the tool parameter at all). However, when I tried to call the function this way: test(4, 2, 3, 'tool'), it once again threw an error at me, complaining about how it can't add together ints and strings.
What is going on?

*args must be at the end of a function call. This is because if there are arguments after *args, Python has no way of knowing when *args ends and the rest of the arguments begin. If there are a set number of arguments at the start, then *args, it knows to stop at the end of the function.
Python is an interpreted language, so it will read the function from left to right and assign variables as it goes. Take the following:
def foo(bar, *args):
print("Hello, world!", bar, args)
If I pass in foo(3, 4, 5, 6) Python says, "Okay, we'll set bar to 3. Then, the rest of our arguments go into args. That's (4, 5, 6)".
Now with the arguments the other way round:
def foo(*args, bar):
print("Hello, world!", bar, args)
With the same arguments, Python will say, "The rest of the arguments can be put into args. That's (3, 4, 5, 6). Wait, what about bar? We have nothing left!" And so it throws an error.
With your function, test, you can't input three numbers and a string if you're adding up *args. You have to pass tool in first, then the numbers.

It is just because of the interpreter (or compiler in other languages' cases). When you define a function the interpreter looks for arguments, then extra arguments, and then keyword arguments; for properly explaining:
In this case, the interpreter will find just one argument:
def (myArg):
In this case, the interpreter will find an argument and 'remaining' arguments, so it knows how to map the first argument and then the others.
def (myArg, *args):
But in this case, the interpreter looks for a list of arguments so it will take all of them and pack them into args; what happens to myArg then?
def(*args, myArg):
There are no more arguments because it already packed all of them into args, just because the interpreter doesn't know when args ends.

Related

passing default parameters with varargs in function in python

when I try the following, I get error in the function definition itself.
>>> def mymap(*seq,pad=None):
File "<stdin>", line 1
def mymap(*seq,pad=None):
SyntaxError: invalid syntax
I am trying to give default value for the parameter pad.
but then, I tried this and it works (for wrong reason):
>>> def mymap(pad=None,*seq):
... print seq
>>> mymap([1,2,3],[4,5,6])
([4, 5, 6],)
[(4,)]
>>>
It is not printing the tuple of seq which should be ([1,2,3],[4,5,6]).
What you really want here is for pad to be a keyword-only parameter.
One of the major changes in 3.0 was designing function parameters and arguments to, among other things, provide exactly the feature you're looking for. In fact, your first version works exactly as you'd hope it to. But if you want to stick with 2.x, you don't get any of the new features in 3.x.
So, you have no choice but to fake it:
def mymap(*seq, **kwargs):
pad = kwargs.pop('pad', None)
if kwargs:
raise TypeError("mymap() got an unexpected keyword argument '{}'".format(kwargs.keys()[0]))
print seq
This does very nearly the exact same thing as the equivalent Python 3 code. Of course it's more complicated, a lot less clear, slower, and opaque to introspection… all of which is exactly why keyword-only parameters were added in 3.0. But if you need it, and you can't use Python 3.x, this is what you have to do. (Just be glad you're not trying to write C-API functions.)
You seem to be mixing up two entirely independent things: a parameter having a default value (which I assume is what you mean by the term "default parameter", which doesn't really mean anything), and being keyword-only.
You've already got a parameter with a default value, in your second version. You can see that easily: call mymap(), and it succeeds, with pad getting its default value of None (and seq being empty).
But you want it to also be a keyword-only parameter, so it doesn't steal the first positional argument. And that's the part you can't do in 2.x.
If you want to know more, PEP 3012 explains the keyword-only feature, and Arguments and parameters attempts to gather all the relevant documentation links, and summarize how everything fits together.
It looks like you are inputting the args [1,2,3] and [4,5,6] as two seperate arguments. They are not in a tuple.
mymap([1,2,3], [4,5,6]) << in this example, from your code, the [1,2,3] is being passed in for pad and the [4,5,6] is being passed in for seq. That's why printing seq results in [4,5,6]
Also, named arguments like pad, must come before *args or **kwargs.
For example:
mymap(None, [1,2,3],[4,5,6]) #passing None for pad
prints:
([1,2,3], [4,5,6])

func(*args, **kwargs, x) throwing invalid syntax

Studied myself into a corner again...
def superfunction(*args, **kwargs, k):
^
SyntaxError: invalid syntax
Whats the rule Im breaking here? It seems that youre not supposed to mix 'regular' variables with * variables, but I cant find anyone to confirm or deny this. I read somewhere (and I cant find in now of course) that some types of arguments have to come first, I believe keyword arguments, which may or may not be part of my issue.
Try this:
def superfunction(k, *args, **kwargs):
The **kwargs variable keyword parameter must be the last part in the function declaration. Second-to-last, the *args variable position parameter. (In Python 3.x only, you can also have keyword-only parameters between *args and **kwargs.) And in the first places, the positional parameters - that's the correct way to declare function parameters. Take a look at this post for additional details.
For the full reference, see the Function definitions section in Python 3.x or Python 2.x.
Syntax should be like this:
def superfunction(k, *args, **kwargs):
First you give all the positional arguments, then non-keyword arguments, and then keyword arguments.

Why a calling function in python contains variable equal to value?

I have started to learn python, and I would like to ask you about something which I considered a little magic in this language.
I would like to note that before learning python I worked with PHP and there I haven't noticed that.
What's going on - I have noticed that some call constructors or methods in Python are in this form.
object.call(variable1 = value1, variable2 = value2)
For example, in FLask:
app.run(debug=True, threaded=True)
Is any reason for this convention? Or is there some semantical reason outgoing from the language fundamentals? I haven't seen something like that in PHP as often as in Python and because I'm really surprised. I'm really curious if there is some magic or it's only convention to read code easier.
These are called keyword arguments, and they're usually used to make the call more readable.
They can also be used to pass the arguments in a different order from the declared parameters, or to skip over some default parameters but pass arguments to others, or because the function requires keyword arguments… but readability is the core reason for their existence.
Consider this:
app.run(True, False)
Do you have any idea what those two arguments mean? Even if you can guess that the only two reasonable arguments are threading and debugging flags, how can you guess which one comes first? The only way you can do it is to figure out what type app is, and check the app.run method's docstring or definition.
But here:
app.run(debug=True, threaded=False)
It's obvious what it means.
It's worth reading the FAQ What is the difference between arguments and parameters?, and the other tutorial sections near the one linked above. Then you can read the reference on Function definitions for full details on parameters and Calls for full details on arguments, and finally the inspect module documentation on kinds of parameters.
This blog post attempts to summarize everything in those references so you don't have to read your way through the whole mess. The examples at the end should also serve to show why mixing up arguments and parameters in general, keyword arguments and default parameters, argument unpacking and variable parameters, etc. will lead you astray.
Specifying arguments by keyword often creates less risk of error than specifying arguments solely by position. Consider this function to compute loan payments:
def pmt(principal, interest, term):
return **something**;
When one tries to compute the amortization of their house purchase, it might be invoked thus:
payment = pmt(100000, 4.2, 360)
But it is difficult to see which of those values should be associated with which parameter. Without checking the documentation, we might think it should have been:
payment = pmt(360, 4.2, 100000)
Using keyword parameters, the call becomes self-documenting:
payment = pmt(principal=100000, interest=4.2, term=360)
Additionally, keyword parameters allow you to change the order of the parameters at the call site, and everything still works correctly:
# Equivalent to previous example
payment = pmt(term=360, interest=4.2, principal=100000)
See http://docs.python.org/2/tutorial/controlflow.html#keyword-arguments for more information.
They are arguments passed by keywords. There is no semantical difference between keyword arguments and positional arguments.
They are often used like "options", and provide a much more readable syntax for this circumstance. Think of this:
>>> sorted([2,-1,3], key=lambda x: x**2, reverse=True)
[3, 2, -1]
Versus(python2):
>>> sorted([2,-1,3], None, lambda x: x**2, True)
[3, 2, -1]
In this second example can you tell what's the meaning of None or True?
Note that in keyword only arguments, i.e. arguments that you can only specify using this syntax, were introduced in python3. In python2 any argument can be specified by position(except when using **kwargs but that's another issue).
There is no "magic".
A function can take:
Positional arguments (args)
Keyworded arguments (kwargs)
Always is this order.
Try this:
def foo(*args, **kwargs):
print args
print kwargs
foo(1,2,3,4,a=8,b=12)
Output:
(1, 2, 3, 4)
{'a': 8, 'b': 12}
Python stores the positional arguments in a tuple, which has to be immutable, and the keyworded ones in a dictionary.
The main utility of the convention is that it allows for setting certain inputs when there may be some defaults in between. It's particularly useful when a function has many parameters, most of which work fine with their defaults, but a few need to be set to other values for the function to work as desired.
example:
def foo(i1, i2=1, i3=3, i4=5):
# does something
foo(1,2,3,4)
foo(1,2,i4=3)
foo(1,i2=3)
foo(0,i3=1,i2=3,i4=5)

Using named arguments with variable length un-named arguments in Python

I apologize if this question has already been asked/answered, I would have expected that to be the case but was unable to find any related questions...
I'd like to create a python function that takes two mandatory arguments, one named argument, and some unknown number of other, non-named arguments as so:
def my_function(arg1, arg2, arg3=None, *other_args):
pass
Is this possible in Python 2.x?
Can a function accept named arguments in addition to a variable length argument list?
I believe the answer is 'no', in which case I'm thinking the only solution available to me would be something similar to the following:
def my_function(arg1, arg2, **kwargs):
arg3 = kwargs["arg3"]
other_args = kwargs["other_args"]
Is that correct?
That syntax is certainly valid, but I think you mean can you write the function signature such that arg3 is only bound if it's used as a named parameter (e.g. my_function(1, 2, arg3 = 3)), and otherwise to have all arguments past the first two be caught by *other_args, in which case the answer is no. Optional arguments can be specified by naming, but they're also positional like normal arguments and are filled in if enough parameters are available, before resorting to catch-alls like *args or **kwargs.
I would probably write it exactly as you did, using keyword arguments

Advantages of using *args in python instead of passing a list as a parameter

I'm going through python and I was wondering what are the advantages of using the *args as a parameter over just passing a list as a parameter, besides aesthetics?
Generally it's used to either pass a list of arguments to a function that would normally take a fixed number of arguments, or in function definitions to allow a variable number of arguments to be passed in the style of normal arguments. For instance, the print() function uses varargs so that you can do things like print(a,b,c).
One example from a recent SO question: you can use it to pass a list of range() result lists to itertools.product() without having to know the length of the list-of-lists.
Sure, you could write every library function to look like this:
def libfunc1(arglist):
arg1 = arglist[1]
arg2 = arglist[2]
...
...but that defeats the point of having named positional argument variables, it's basically exactly what *args does for you, and it results in redundant braces/parens, since you'd have to call a function like this:
libfunc1([arg1val,arg2val,...])
...which looks very similar to...
libfunc1(arg1val,arg2val,...)
...except with unnecessary characters, as opposed to using *args.
That is for flexibility.
It allows you to pass on the arguments, without knowing how much you need. A typical example:
def f(some, args, here): # <- this function might accept a varying nb of args
...
def run_f(args, *f_args):
do_something(args)
# run f with whatever arguments were given:
f(*f_args)
Make sure to check out the ** keyword version.

Categories

Resources