passing default parameters with varargs in function in python - 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])

Related

Why positional arguments need to be specified before keyword arguments in Python?

I understand passing positional arguments first and then passing the keyword arguments is a rule in python.
And that's why these are wrong:
def fun(x,y):
print(x,y)
fun3(y=4,3)
SyntaxError: positional argument follows keyword argument
and this is wrong too.
def fun2(**kwargs,*args):
File "<stdin>", line 1
def fun2(**kwargs,*args):
^
SyntaxError: invalid syntax
Python strictly checks that I am passing positional arguments first.
What I don't understand. Why?
Isn't this intuitive:
def test(x,y,z):
print(x,y,z)
and then calling the function as
test(z=3,1,2)
should first assign keyword argument z's value 3 and then sequentially assign 1 and 2 to the remaining unassigned variables x and y respectively.
It's not even that python doesn't check if the variable is already assigned or not, because the following gives an error like:
def test2(x,y):
print(x,y)
test2(1,x=1)
TypeError: test2() got multiple values for argument 'x'
Got multiple values for x. So python definitely knows which variable have already received the values. Why can't it then just check for which variables haven't received the values and then assign them those positional argument values sequentially.
I am making notes for my reference and I am stuck while writing anything about the logic behind this behavior of python.
See it seems your argument is valid.
But I like to point out when you said, "Isn't this intuitive:"
Tell me any other object oriented language where you have seen this, and is quite popular.
So the thing is python is popular because it is very easy to adapt to,
I don't know about you but I switched to python recently from C, and there I use to
create functions like length, reverse, sort etc. in python the exact most common names are present of the similar function. It is so easy to adapt, unlike other language where they change name or insert these functions hidden in some utils class like java.
To answering your question.
Like other say it will increase complexity.
And this is why other popular object oriented language didn't adopt it.
And so since its not available in other popular language.
Python didn't adopt it, cause it would make adapting to python difficult. And also due to underlying reason that it would make things complex.
"Isn't this intuitive:" for me, politely, NO, it is not intuitive.
If I pass argument at position 0 in function call, it would expect it to go to position 0 argument in function defination. Cause That's how I did in C. And I believe cause that's how its done in most object oriented language.
Python functions follow the order of the arguments when it is defined and assigns the value to them in the same order when we call the function. Doing what you want to do will confuse it like you tried to do in the second problem (TypeError: test2() got multiple values for argument 'x').
As we get errors by doing so, it is still better but if such feature had been added to python, there maybe some more bugs (especially which won't produce errors). E.g, assigning a value to an argument which is wrong as per our logic.

Why would an API author prevent positional parameters in Python?

Implementing some Neural Network with tensorflow, I've faced a method which parameters have took my attention. I'm talking about tf.nn.sigmoid_cross_entropy_with_logits (Documentation here).
The first parameter it receives as first parameter _sentinel=None which, according to the documentation:
_sentinel: Used to prevent positional parameters. Internal, do not use.
I understand that by having this parameter, next ones have to be named instead of positional is this one don't have to be used, but my question is. In which cases does prevent positional parameters have some benefit? What is their main goal to use this? Because I could also run
tf.nn.sigmoid_cross_entropy_with_logits(None, my_labels, my_logits)
being all arguments positional. Anyway, I want to clarify that my question is not focused in TensorFlow, it's just the example that I have found.
Positional parameters couple the caller and receiver on the order of the parameters. It makes refactoring the order of the reciver's parameters more difficult.
For example, if I have
def foo(a, b, c):
do_stuff(a,b,c)
and I decide, for reasons, perhaps I want to make a partial function or whatever, that it would be better to have
def foo(b, a, c):
do_stuff(a,b,c)
But now I have callers in the wild and it would be very rude to change my contract, so I'm stuck.
Sandi Metz in Practical Object-Oriented Design in Ruby also addresses this. (I know this is python, but oop is oop)
When the code [is changed to use keyword arguments], it lost its dependency
on argument order but it gained a dependency on the names of the keys
in the [keyword arguments]. This change is healthy. The new dependency is
more stable than the old, and thus this code faces less risk of being
forced to change. Additionally, and perhaps unexpectedly, the [keywords]
provides one new, secondary benefit: The key names in the hash furnish
explicit documentation about the arguments. This is a byproduct of
using a hash but the fact that it is unintentional makes it no less
useful. Future maintainers of this code will be grateful for the
information.
Keyword arguments are also nice if you have a lot of parameters. Order is easy to get wrong. It may also make a nicer API in the opinion of the authors.
PEP-3102 also addresses this, but I find the rationale unsatisfying from the perspective of "why would I choose to design something like this"
The current Python function-calling paradigm allows arguments to be
specified either by position or by keyword. An argument can be filled
in either explicitly by name, or implicitly by position.
There are often cases where it is desirable for a function to take a
variable number of arguments. The Python language supports this using
the 'varargs' syntax (*name), which specifies that any 'left over'
arguments be passed into the varargs parameter as a tuple.
One limitation on this is that currently, all of the regular argument
slots must be filled before the vararg slot can be.
This is not always desirable. One can easily envision a function which
takes a variable number of arguments, but also takes one or more
'options' in the form of keyword arguments. Currently, the only way to
do this is to define both a varargs argument, and a 'keywords'
argument (**kwargs), and then manually extract the desired keywords
from the dictionary.
What is the use for keyword only parameters:
For some function, it is impossible to do otherwise (ex: print(a, b, end=''))
It prevents you from making silly mistakes, consider the following example:
# if it wasn't made with kw-only parameters, this would return 3
>>> sorted(3, 1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: sorted expected 1 arguments, got 2
>>> sorted((1,2), reverse=True)
[2, 1]
It allows you to change things later:
# if
def sorted(iterable, reverse=False)
# becomes
def sorted(iterable, key=None, reverse=False)
# you can guarantee backwards compatibility
First, a caveat that I can't know the intention of the person who wrote that. However, I can offer reason why “prevent positional parameters” might be desirable.
It's often important that a parameter be keyword-only, that is, it must be used only by name. The parameter is not conceptually an input to the function's purpose; it's more a modifier (change the behaviour in this way), or an external resource (here is the log file to emit your messages to), etc.
For that reason, Python 3 now allows you to define, in the signature of the function, specific parameters as keyword-only parameters. The change is documented in PEP 3102 Keyword-only arguments along with rationale.

Python - Sending multiple values for one argument to a function

I am a few days new to Python so if this is silly please excuse me..
Is there a method to sending multiple variables to a single function? As an example:
pe.plot_chart(conn,7760,'DataSource1',123,save=True)
This above function takes a connection to SQL where it pulls data for unique ID 7760 from datasource1 (uniqueid 123). Can I use some method to send multiple criteria for the DataSource1 field? e.g.
pe.plot_chart(conn,7760,['DataSource1','DataSource2'],[123,345],save=True)
pe.plot_chart was created by me, so any modifications that have to be made to it to make it work are fine
Is this type of operation possible to perform?
EDIT: Adding on some extra info.
The plot_chart function.. well it plots a chart, and saves it to the location above. Each call of the function produces one graph, I was hoping that by sending multiple values for a parameter I could have the function dynamically add more series to the plot.
So if I send 4 data sources to the function, I will end up with 4 lines on the plot. For this reason I am not sure looping through a data source collection would be good (will just produce 4 plots with one line?)
Yes you can send multiple arguments to a function in python, but that shouldn't be a surprise. What you cannot do is having positional arguments after a keyword argument, that is calls like f(1, foo=2, 3) is not allowed (your example is invalid for that reason).
Also you cannot supply multiple values to a single argument in a strict sense, but you can supply an list or tuple to a single argument, that is for example f(1, foo=(2, 3)) is acceptable and your function might interpret that as you are supplying two values to the foo argument (but in reality it's only one tuple).
The downside is that the function must be able to distinguish between a tuple as argument and what is intended as a single argument. The easiest way is to insist on that the argument should be a tuple or at least iterable. The function would have to look somewhat like:
def f(foo, bar):
for x in foo:
do_something(bar, x)
f(bar=fubar, foo=(arg1, arg2, arg3))
f((arg1, arg2, arg3), bar=fubar) # same as previous line
f((arg1, arg2, arg3), fubar) # same as previous line
another more advanced alternative would be to use keyword argument for everything except what would be the multiple arguments by using variable argument list, but this is somewhat clumpsy in python2 as you'll need to supply all arguments as positional unless you manually unpack the keywords arguments, in python3 there is some relief as you can force using of keyword arguments:
def f(*args, bar=fubar):
for x in args:
do_something(bar, x)
f(arg1, arg2, arg3, bar=fubar)
# f(fubar, arg1, arg2, arg3) is not allowed
and then every argument that is not a keyword argument (still those positional arguments has to be the first arguments) will end up in args, and the bar argument is required to be passed as keyword argument.
In python2 the above would need to be:
def f(*args, **kwds):
bar = kwds.get("bar", fubar)
for x in args:
do_something(bar, x)
data_sources = [data_source1, data_source2, data_source3]
for source in data_sources:
pe.plotchart(connection, uniqueid = 7760, source...)
There's various ways to approach this - if you want to send an iterable (like a list) to your function once and have the function iterate through them, you can do that. You can also call the function from a loop. If the other parameters are going to change for each iteration, look into "zip", which is useful for pairing data for looping.
It's possible to pair data source specifications with unique IDs in your case. Here is a simple approach with lists of tuples:
def myFunc(values):
for v in values:
print v[0], v[1]
myFunc([("hello", 1), ("world", 2)])
The list elements could also be expanded into classes if there is a need for more description for each line to plot. The benefit of this flip is that you are handling one list of line descriptors (which are represented by tuples), not loosely coupled "arguments".
The output BTW is this:
hello 1
world 2
Your specific case would change into this
pe.plot_chart(conn,7760,[('DataSource1',123),('DataSource2',345)],save=True)

Mixing *vargs and **kargs arguments in function call

def func(*v, **k): pass
func(**{'a': 1}, *(1, 2, 3)) # ERROR...
func(a=1, *(1, 2, 3)) # OK...
I don't get why this first doesn't work, instead the second does.
Someone could just tell "because the implementation says so", but I would like also to know why the implementation says so. Couldn't the implementation translate the first to the second in order to make this call work?
first, the second line works only if the a parameter is the last (the forth). for example, the following code will not work:
def func(a,b,c,d):
pass
func(a=1, *(1, 2, 3))
And to you question, I think the problem with the first line:
func(**{'a': 1}, *(1, 2, 3))
is that you can have multiple values for the same parameter this way, if the dictionary contains one of the first 3 parameters.
the difference is that the dictionary can be a variable and have different value on different runs so this code always considered illegal
Passing positional arugments and keyword arguments like this is part of the language's syntax, not a run-time feature. That is, *(1,2,3) does not simply create a special object that is passed to the function when it is called and "somehow" used to assign values to the defined parameters. As such, allowing this kind of flexibility in the ordering would come at the cost of greatly complicating the parser for no real benefit.

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)

Categories

Resources