git.net

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Questioning the effects of multiple assignment


On 7/07/20 7:21 PM, Mike Dewhirst wrote:
> -------- Original message --------

For comparison, here's the original form:-

 >>> def f( a, *b, c=0 ):
...     print( a, type( a ) )
...     print( c, type( c ) )
...     print( b )
...
 >>> f( 1, 'two', 3, 'four' )
1 <class 'int'>
0 <class 'int'>
('two', 3, 'four')


> Shouldn't that def be ...
> 
>  >>> def f(a, c=0, *b):
> ???

It might appear that way, but in v3.7*, they are not:-

 >>> def f(a, c=0, *b):
...     print( a, type( a ) )
...     print( c, type( c ) )
...     print( b, type( b ) )
...
 >>> f( 1, 'two', 3, 'four' )
1 <class 'int'>
two <class 'str'>                #####
(3, 'four') <class 'tuple'>      #####

and even worse when we attempt to specify "c" as a keyword argument:

 >>> f( 1, 'two', 3, c='four' )
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
TypeError: f() got multiple values for argument 'c'

 >>> f( 1, c='four', 'two', 3 )
   File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument

 >>> f( 1, 'four', 'two', 3 )
1 <class 'int'>
four <class 'str'>
('two', 3) <class 'tuple'>


Please remember also, that the idea of interposing a keyword-argument 
was by way of illustration. The original spec was to expand the API to 
accept either a series of scalars or equivalent values as a tuple, 
without (also) changing the API to require the new/tuple option be 
implemented as a keyword-argument.


However, to answer the question: the method of assigning the arguments' 
values to parameters is to start from the left, but upon reaching a 
*identifier to re-start by allocating from the right. This will leave 
zero or more values 'in the middle', to be tuple-ified as the *identifier.

Otherwise, if the allocation were l-to-r and "greedy", there would never 
be any values assigned to 'later' parameters!


For your reading pleasure:-

> Python Reference Manual: 6.3.4. Calls
> A call calls a callable object (e.g., a function) with a possibly empty
> series of arguments:
> ...
> If there are more positional arguments than there are formal parameter
> slots, a TypeError exception is raised, unless a formal parameter using
> the syntax *identifier is present; in this case, that formal parameter
> receives a tuple containing the excess positional arguments (or an empty
> tuple if there were no excess positional arguments).
> https://docs.python.org/dev/reference/expressions.html#calls


* I was remiss in not stating that this project is (?still) running with 
Python v3.7. Apologies! (it was established some time ago, and evidently 
the client has not seen fit to even consider upgrading as part of any 
sprint, to-date. Note to self...)

So, please be aware of:
https://docs.python.org/3/whatsnew/3.8.html#positional-only-parameters
https://www.python.org/dev/peps/pep-0570/


If you are running a more recent release, perhaps you might like to 
re-run the snippets, experiment, and document any contrary findings?
-- 
Regards =dn