Mixing *vargs and **kargs arguments in function call - python

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.

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.

How do I use the output of a function as the input for another function inside a function

I am currently studying Python and hoping someone could help me.
I'm fairly new to coding so would be really helpful if its explained well.
Lets say I have a function called function1 that returns:
return (row, column)
Now I am writing another function called say function2.
Within this function I need to call say:
exampleItem.exampleName(row, column, name)
How do I use the output of the function1 which is the row and column as the row and column arguments in the above line from function2?
I really hope this makes sense as I got seriously penalized for not writing a question properly before because I didn't realize the best practice here.
In all versions of Python you can do:
row, column = function1()
exampleName(row, column, name)
In more recent versions (3.5+) you can use unpacking to do things like:
exampleName(*function1(), name)
For further reading see: PEP 448 -- Additional Unpacking Generalizations.
You can use the star * to unpack the result --which is a tuple-- of calling function function1 after you place it as an argument inside the other function. This results in providing the elements returned from function1 as positional arguments in the second:
exampleItem.exampleName(*function1(), name)
In Python 2.x you can do the same but, you need to supply the remaining positional arguments in keyword form in order to get it to work with *:
exampleItem.exampleName(*function1(), name=name)
this also works on Python 3.x so you have no issues with portability.
Of course, unpacking in a previous statement with row, column = function1() and then providing them to the second function by position with:
exampleItem.exampleName(row, column, name)
is another option. It really falls down to preference in the end :-)
This is called "tuple unpacking", which takes the parts of a tuple (or list) and uses them as arguments.
If f1(row, column) is the function returning (row, column) (for the sake of a simple example):
a = f1(3, 4)
b = exampleItem.exampleName(*a, name="fish")
# Or, as a one-liner:
b = exampleItem.exampleName(*f1(3,4), name="fish")
The major limitation here is that after the tuple-unpacked argument (a above, you unpack with a *), all further arguments must be assigned by name, not position.
If you can't give specific argument names, and if you're still using Python 2, you'd need to do something like:
x, y = f1(3, 4) # unpacks the length-2 tuple into two variables
b = exampleItem.exampleName(x, y, "fish")
Which cannot be made into a one-liner. Python 3 doesn't require that, though, so you could do the first example without needing to use name= on the third argument if you're in Python 3.
Another relevant note: If you use ** instead, you can unpack a dictionary, which does the same thing as tuple unpacking except for named arguments instead of positional arguments.

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])

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)

Parameter names in Python functions that take single object or iterable

I have some functions in my code that accept either an object or an iterable of objects as input. I was taught to use meaningful names for everything, but I am not sure how to comply here. What should I call a parameter that can a sinlge object or an iterable of objects? I have come up with two ideas, but I don't like either of them:
FooOrManyFoos - This expresses what goes on, but I could imagine that someone not used to it could have trouble understanding what it means right away
param - Some generic name. This makes clear that it can be several things, but does explain nothing about what the parameter is used for.
Normally I call iterables of objects just the plural of what I would call a single object. I know this might seem a little bit compulsive, but Python is supposed to be (among others) about readability.
I have some functions in my code that accept either an object or an iterable of objects as input.
This is a very exceptional and often very bad thing to do. It's trivially avoidable.
i.e., pass [foo] instead of foo when calling this function.
The only time you can justify doing this is when (1) you have an installed base of software that expects one form (iterable or singleton) and (2) you have to expand it to support the other use case. So. You only do this when expanding an existing function that has an existing code base.
If this is new development, Do Not Do This.
I have come up with two ideas, but I don't like either of them:
[Only two?]
FooOrManyFoos - This expresses what goes on, but I could imagine that someone not used to it could have trouble understanding what it means right away
What? Are you saying you provide NO other documentation, and no other training? No support? No advice? Who is the "someone not used to it"? Talk to them. Don't assume or imagine things about them.
Also, don't use Leading Upper Case Names.
param - Some generic name. This makes clear that it can be several things, but does explain nothing about what the parameter is used for.
Terrible. Never. Do. This.
I looked in the Python library for examples. Most of the functions that do this have simple descriptions.
http://docs.python.org/library/functions.html#isinstance
isinstance(object, classinfo)
They call it "classinfo" and it can be a class or a tuple of classes.
You could do that, too.
You must consider the common use case and the exceptions. Follow the 80/20 rule.
80% of the time, you can replace this with an iterable and not have this problem.
In the remaining 20% of the cases, you have an installed base of software built around an assumption (either iterable or single item) and you need to add the other case. Don't change the name, just change the documentation. If it used to say "foo" it still says "foo" but you make it accept an iterable of "foo's" without making any change to the parameters. If it used to say "foo_list" or "foo_iter", then it still says "foo_list" or "foo_iter" but it will quietly tolerate a singleton without breaking.
80% of the code is the legacy ("foo" or "foo_list")
20% of the code is the new feature ("foo" can be an iterable or "foo_list" can be a single object.)
I guess I'm a little late to the party, but I'm suprised that nobody suggested a decorator.
def withmany(f):
def many(many_foos):
for foo in many_foos:
yield f(foo)
f.many = many
return f
#withmany
def process_foo(foo):
return foo + 1
processed_foo = process_foo(foo)
for processed_foo in process_foo.many(foos):
print processed_foo
I saw a similar pattern in one of Alex Martelli's posts but I don't remember the link off hand.
It sounds like you're agonizing over the ugliness of code like:
def ProcessWidget(widget_thing):
# Infer if we have a singleton instance and make it a
# length 1 list for consistency
if isinstance(widget_thing, WidgetType):
widget_thing = [widget_thing]
for widget in widget_thing:
#...
My suggestion is to avoid overloading your interface to handle two distinct cases. I tend to write code that favors re-use and clear naming of methods over clever dynamic use of parameters:
def ProcessOneWidget(widget):
#...
def ProcessManyWidgets(widgets):
for widget in widgets:
ProcessOneWidget(widget)
Often, I start with this simple pattern, but then have the opportunity to optimize the "Many" case when there are efficiencies to gain that offset the additional code complexity and partial duplication of functionality. If this convention seems overly verbose, one can opt for names like "ProcessWidget" and "ProcessWidgets", though the difference between the two is a single easily missed character.
You can use *args magic (varargs) to make your params always be iterable.
Pass a single item or multiple known items as normal function args like func(arg1, arg2, ...) and pass iterable arguments with an asterisk before, like func(*args)
Example:
# magic *args function
def foo(*args):
print args
# many ways to call it
foo(1)
foo(1, 2, 3)
args1 = (1, 2, 3)
args2 = [1, 2, 3]
args3 = iter((1, 2, 3))
foo(*args1)
foo(*args2)
foo(*args3)
Can you name your parameter in a very high-level way? people who read the code are more interested in knowing what the parameter represents ("clients") than what their type is ("list_of_tuples"); the type can be defined in the function documentation string, which is a good thing since it might change, in the future (the type is sometimes an implementation detail).
I would do 1 thing,
def myFunc(manyFoos):
if not type(manyFoos) in (list,tuple):
manyFoos = [manyFoos]
#do stuff here
so then you don't need to worry anymore about its name.
in a function you should try to achieve to have 1 action, accept the same parameter type and return the same type.
Instead of filling the functions with ifs you could have 2 functions.
Since you don't care exactly what kind of iterable you get, you could try to get an iterator for the parameter using iter(). If iter() raises a TypeError exception, the parameter is not iterable, so you then create a list or tuple of the one item, which is iterable and Bob's your uncle.
def doIt(foos):
try:
iter(foos)
except TypeError:
foos = [foos]
for foo in foos:
pass # do something here
The only problem with this approach is if foo is a string. A string is iterable, so passing in a single string rather than a list of strings will result in iterating over the characters in a string. If this is a concern, you could add an if test for it. At this point it's getting wordy for boilerplate code, so I'd break it out into its own function.
def iterfy(iterable):
if isinstance(iterable, basestring):
iterable = [iterable]
try:
iter(iterable)
except TypeError:
iterable = [iterable]
return iterable
def doIt(foos):
for foo in iterfy(foos):
pass # do something
Unlike some of those answering, I like doing this, since it eliminates one thing the caller could get wrong when using your API. "Be conservative in what you generate but liberal in what you accept."
To answer your original question, i.e. what you should name the parameter, I would still go with "foos" even though you will accept a single item, since your intent is to accept a list. If it's not iterable, that is technically a mistake, albeit one you will correct for the caller since processing just the one item is probably what they want. Also, if the caller thinks they must pass in an iterable even of one item, well, that will of course work fine and requires very little syntax, so why worry about correcting their misapprehension?
I would go with a name explaining that the parameter can be an instance or a list of instances. Say one_or_more_Foo_objects. I find it better than the bland param.
I'm working on a fairly big project now and we're passing maps around and just calling our parameter map. The map contents vary depending on the function that's being called. This probably isn't the best situation, but we reuse a lot of the same code on the maps, so copying and pasting is easier.
I would say instead of naming it what it is, you should name it what it's used for. Also, just be careful that you can't call use in on a not iterable.

Categories

Resources