[Tutor] Defining variable arguments in a function in python

Avi Gross avigross at verizon.net
Sun Dec 30 00:07:20 EST 2018


I have my usual off the wall answer.

OK, seriously. Not exactly an answer but perhaps an experiment.

The question was how to have a non-named first argument to a function with
some form of default. 

As was pointed out, this does not fit well with being able to have python
gather all positional arguments after it as well as all keyword arguments.

But bear with me. Say I want to have a way to signal that I want a default
for the first argument?

An empty comma fails but try this:

def hello(a, *n, **m) :
	if a == None: a=5
	print(a)
	print(*n)
	print(**m)

The above says "a" is required. It can be followed by any number of
positional args gathered into "n" and any number of keyword args gathered
into "m"

But what if you define a sentinel to watch for such as None, in the above?

If the first and only arg is None, it switches to the default of 5.

>>> hello(None)
5

Add a few more args and it properly takes it.

>>> hello(1,2,3)
1
2 3

Switch the first to None:

>>> hello(None,2,3)
5
2 3

The keywords don't work for print but no biggie.

But is this only for None? What I say any negative arg is replaced by 5?

def hello(a, *n, **m) :
	if a < 0: a=5
	print(a)
	print(*n)

Seems to work fine:

>>> hello(-666, 2, 3, 4)
5
2 3 4

And I wonder if we can use the darn ellipsis for something useful?

def hello(a, *n, **m) :
	if a == ... : a=5
	print(a)
	print(*n)

>>> hello(1,2,3)
1
2 3
>>> hello(...,2,3)
5
2 3
>>> hello(...,2,...)
5
2 Ellipsis

OK, all kidding aside, is this helpful? I mean if you want a function where
you MUST give at least one arg and specify the first arg can be some odd
choice (as above) and then be replaced by  a default perhaps it would be
tolerable to use None or an Ellipsis.

Or on a more practical level, say a function wants an input from 1 to 10.
The if statement above can be something like:

>>> def hello(a, *n, **m) :
	if not (1 <= a <= 10) : a=5
	print(a)
	print(*n)

	
>>> hello(1,2,3)
1
2 3
>>> hello(21,2,3)
5
2 3
>>> hello(-5,2,3)
5
2 3
>>> hello("infinity and beyond",2,3)
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    hello("infinity and beyond",2,3)
  File "<pyshell#28>", line 2, in hello
    if not (1 <= a <= 10) : a=5
TypeError: '<=' not supported between instances of 'int' and 'str'

As expected, it may take a bit more code such as checking if you got an int
but the idea may be solid enough. It is NOT the same as having a default
from the command line but it may satisfy some need.

Other than that, I fully agree that the current python spec cannot support
anything like this in the function definition.

Side note: To spare others, I sent Steven alone a deeper reply about ways to
select random rows from a pandas DataFrame. I am still learning how pandas
works and doubt many others here have any immediate needs.









-----Original Message-----
From: Tutor <tutor-bounces+avigross=verizon.net at python.org> On Behalf Of
Steven D'Aprano
Sent: Saturday, December 29, 2018 6:02 AM
To: tutor at python.org
Subject: Re: [Tutor] Defining variable arguments in a function in python

On Sat, Dec 29, 2018 at 11:42:16AM +0530, Karthik Bhat wrote:
> Hello,
> 
>         I have the following piece of code. In this, I wanted to make 
> use of the optional parameter given to 'a', i.e- '5', and not '1'
> 
> def fun_varargs(a=5, *numbers, **dict):
[...]
> 
> fun_varargs(1,2,3,4,5,6,7,8,9,10,Jack=111,John=222,Jimmy=333)
> 
> How do I make the tuple 'number' contain the first element to be 1 and not
2?


You can't. Python allocates positional arguments like "a" first, and only
then collects whatever is left over in *numbers. How else would you expect
it to work? Suppose you called:

fun_varargs(1, 2, 3)

wanting a to get the value 1, and numbers to get the values (2, 3). And then
immediately after that you call 

fun_varargs(1, 2, 3)

wanting a to get the default value 5 and numbers to get the values (1, 2,
3). How is the interpreter supposed to guess which one you wanted?

If you can think of a way to resolve the question of when to give "a" 
the default value, then we can help you program it yourself:


def func(*args, **kwargs):
    if condition:
        # When?
        a = args[0]
        numbers = args[1:]
    else:
        a = 5  # Default.
        numbers = args
    ...

But writing that test "condition" is the hard part.




--
Steve
_______________________________________________
Tutor maillist  -  Tutor at python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor



More information about the Tutor mailing list