Verbose and flexible args and kwargs syntax

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sun Dec 11 20:11:00 EST 2011


On Mon, 12 Dec 2011 00:44:38 +0100, Eelco Hoogendoorn wrote:

>>  No more so than any other form of punctuation. Plus and minus + - may
>>  be so common that just about everyone knows it, but how about | == @ %
>>  and even . (dot)? None of these things will be obvious to newbies who
>>  have never programmed before. Oh well.
> 
>>  Some things you just have to learn.
> 
> 
> Yes, some things you just have to learn. Nonetheless, I strongly prefer
> explicit logical operators over |, would much rather have 'equals'
> instead of ==, which is stylistic in line with 'is' and explicitly
> distinguishes between equality and identity comparisons.

No more, or less, explicit than the difference between "==" and "is". 


> As for %; it is
> entirely unclear to me why that obscure operation ever got its own
> one-character symbol. Ill take 'mod', or even better, 'modulus' any day
> of the week.

Modulo is hardly an obscure operation. "What's the remainder...?" is a 
simple question that people learn about in primary school. 

And you can blame C for the use of % instead of mod or modulo.


> The dot is clearly quantitatively in another realm here. 90% of typical
> python code is attribute accesses.

I can't imagine what sort of Python code you have seen that you consider 
90% attribute access "typical". I've just run the Python tokenizer over 
my startup.py file, and I get these results:

{'COMMENT': 24, 'DEDENT': 29, 'NL': 46, 'NAME': 256, "':'": 30, 
'NEWLINE': 83, "'-'": 1, 'NUMBER': 1, "'['": 1, "','": 17, "')'": 37, 
"'('": 37, "'%'": 2, "'.'": 48, "'=='": 1, "'*'": 1, 'INDENT': 29, "']'": 
1, "'='": 28, 'ENDMARKER': 1, 'STRING': 19}

That gives attribute access being a little less than 7% of the source 
code. For the decimal module, the figure is a little less than 5%.


> The dot is entirely unambigious and
> cannot be mistaken for anything else. It reads like a book.

The dot can be easily mistaken for a comma, or for a bit of grit on the 
monitor, especially at smaller type sizes, or for those with poor 
eyesight.


[...]
>>  It is also misleading because args are not collected into a list, but
>>  into a tuple.
> 
> In case you wanted a tuple youd write tuple(args), obviously. Exactly
> that added flexibility is half of my case in favor. Why shouldnt it be a
> list when I want it to?

What sort of list? A built-in list, or whatever sort of object you get 
when you call the thing currently bound to the name "list"?

If you can supply any function at all, what happens if I write this:

def func(parg, dict(foo), list(bar)): ...

How about this?

def func(parg, myfunc(x)): ...

What is x now? Should Python try to accumulate arguments by position, or 
by keyword, or try both and hope one will succeed? Which order should it 
try first?

I believe that your proposal leads to an over-generalisation "call 
arbitrary functions when handling parameter lists". I don't believe you 
need this added complication. If you want to your var args as a list, 
call list(args) inside your function.


>>  Worse, it suggests that one should be able to generalise to something
>>  like this:
> 
>>  def func(parg, str(args), int(kwargs), my_func(more_args)):
> 
>>  which is incoherent.
> 
> Sorry, but I dont get this point at all. Does ** suggests one should be
> able to generalize to ***? The rules are the rules.

You have missed that the generalization is not just to multiple "chunks" 
of arguments, but also to arbitrary functions. I thought that both ideas 
were equally incoherent, but ironically you suggest about that you should 
be able to call arbitrary functions: tuple, list, attrdict. What else? 
str? int? 


> The real questions, in my mind, are:
> 
> 1) How useful is this added flexibility? Not insanely, but I can see it
> making a lot of code significantly more clean.

I don't. I see it making a small amount of code more verbose and less 
clean.


> And:
> 
> 2) How fundamental is collection packing/unpacking? One can easily argue
> that it is indeed quite fundamental and therefore deserves its own terse
> symbols, I feel.

In Python, tuple unpacking and packing (actually applies to any 
collection, not just tuples) is *very* fundamental. That's why we can do 
things like this:

a, b, c = my_list
x, y = y, x

> However, if more flexibility is indeed deemed
> desirable, such terse syntax quickly gives way to a more verbose one.
> Can you come up with some terse symbols that will be able to express all
> of the below and dont make you wish you hadnt rather typed out the
> names?
> 
> head, tuple(tail) = iterable

In Python 3, that is spelled:

head, *tail = iterable
tail = tuple(tail)


> head, list(tail) = iterable

head, *tail = iterable


> head, str(tail) = somestring

This is ambiguous, I'm not sure what exactly you expect to get as the 
string. It could arguable be any of:

tail = ''.join(map(repr, tail))
tail = ''.join(map(str, tail))
tail = str(tail)

or even

head, tail = somestring[0], somestring[1:]


> head, generator(tail) = mygenerator

And this is most easily spelled:

head, tail = next(mygenerator), mygenerator



-- 
Steven



More information about the Python-list mailing list