Verbose and flexible args and kwargs syntax
Throwing an idea for a PEP out there: It strikes me that the def func(*args, **kwargs) syntax is rather unpytonic. It certainly did not have that 'for line in file' pythonic obviousness for me as a beginner. Plus, asterikses are impossible to google for, so finding out what exactly they do more or less forces you to write a forum post about it. A more readable form occurred to me, which also happens to be more flexible, and which I think is fully compatible with the syntax of the language: def func(parg, list(args), dict(kwargs)) Perhaps this is considered abuse of notation; dict(kwargs) already has a meaning rather different from the one we try to give it here; but then again the context (being inside a function definition) is unique and easily recognizable. An added advantage would be the possibility of using subclasses of dict and list as well; imagine how much more beautiful a lot of code would be if one could say def func(attrdict(kwargs)) Problems im still wrestling with: the same syntax could not be used when calling a function; that lack of symmetry would make things more confusing, not less. Thoughts? -- http://mail.python.org/mailman/listinfo/python-list
Verbose and flexible args and kwargs syntax
Yes, that's just a strict keywordification of the * and ** symbols. The same argument could be made for eliminating the standard algebraic + operator and replacing it with a keyword "__add__". I don't think that's worthwhile. Well, its not quite the same in the sense that algebraic operators are essentially part of 'natural language', or at least extremely widely adopted. They have earned their own special symbols. Argument packing/unpacking is a very specific thing; a small corner of a particular programming language. However, as seen in the light of python 3 head-tail syntax, perhaps the above is not quite true, and one could argue that packing/unpacking of collections is indeed a quite general concept, deserving of its own symbols. Breaking uniformity with that use case would also be a bad thing; ideally, a verbose alternative to all occurances of collection packing/unpacking would be available. That said, a more verbose and flexible syntax would be desirable there too; as of now, the tail is always a list. I havnt read the discussions leading up to those design decisions, but that seems like a compromise to me; something like head,tuple(tail) = someiterable would be preferrable there too, id say -- http://mail.python.org/mailman/listinfo/python-list
Verbose and flexible args and kwargs syntax
As for syntax; what about coopting/integrating with the function annotation syntax? so: def func(args: list, kwargs: attrdict) and correspondingly in the function call? a, b:tuple = someiterable? I guess a rule that interprets every function argument annotated as a subclass of list or dict as a special case would severely restrict its intended use though... -- http://mail.python.org/mailman/listinfo/python-list
Verbose and flexible args and kwargs syntax
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. 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. The dot is clearly quantitatively in another realm here. 90% of typical python code is attribute accesses. The dot is entirely unambigious and cannot be mistaken for anything else. It reads like a book. It's a judgement call as to where a language divides "cryptic punctuation line noise" and "useful short operators", and in my opinion * and ** tuple and dict unpacking fall strongly on the "useful short operators" side. Your opinion may differ, but luckily for me, the BDFL agrees with me :) I also agree that it is a value judgement as to which constructs get their own cryptic symbols and which do not, but the are some reasonable guidelines we should be able to agree upon. Obscure operations should not reserve any of the few available characters. Furthermore, the language should not just be formally consistent, but also easy to grasp at a glance, without deciphering subtle semantics of a blurb of weird characters. (some programming languages obviously disagree, but python, as far as I am allowed to speak for it, does not). And most importantly, if you cant come up with a terse syntax that does everything you want to do, the terse syntax should at best be an alternative to the verbose one. 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? 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. 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. 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. 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 head, list(tail) = iterable head, str(tail) = somestring head, generator(tail) = mygenerator And so on. If not, one has to admit that functionality is being sacrificed on the alter of terseness, which seems like a raw deal to me. -- http://mail.python.org/mailman/listinfo/python-list
Verbose and flexible args and kwargs syntax
There are other means of finding information than Google. Really. This is really only a very minor point in my argument, so I dont want to put the focus on this. But really, no. Googling 'myprogramminglanguage conceptimtryingtofigureout' is my first, second and third line of defence. Yes, I could read the reference manual from top to bottom, and if I already knew about the existence of your article then im sure that would be a great help too. But the situation one finds oneself in is seeing two asterikses and not even being aware they are particular to function definitions/invocations. Im fluent in many different languages and well versed in CS concepts and jargon, but I had no idea what to search for when first trying to figure out the meaning of these symbols, and that does not happen often to me. -- http://mail.python.org/mailman/listinfo/python-list
Verbose and flexible args and kwargs syntax
The above examples are seldom needed in Python because we have one general method to repeatedly split a sequence into head and tail. it = iter(iterable) # 'it' now represents the sequenced iterable head = next(it) # 'it' now represents the tail after removing the head In other words, next(it) encompasses all of your examples and many more. Because 'it' is mutated to represent the tail, it does not need to be rebound and therefore is not. The question in language design is never 'could we do these things before'. The answer is obvious: yes our CPUs are turing complete; we can do anything. The question is; how would we like to do them? So do you think the new head/tail unpacking features in python 3 are entirely uncalled for? I personally quite like them, but I would like them to be more general. -- http://mail.python.org/mailman/listinfo/python-list
Verbose and flexible args and kwargs syntax
> No more, or less, explicit than the difference between "==" and "is". == may be taken to mean identity comparison; 'equals' can only mean one thing. Of course 'formally' these symbols are well defined, but so is brainf*ck Modulo is hardly an obscure operation. "What's the remainder...?" is a simple question that people learn about in primary school. So is 'how much wood would a woodchucker chuck if a woodchucker could chuck wood?'. But how often does that concept turn up in your code? > And you can blame C for the use of % instead of mod or modulo. I didnt know one of Python's design goals was backwards compatibility with C. 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: Yes, that was a hyperbole; but quite an often used construct, is it not? If you can supply any function at all, what happens if I write this: You cannot; only constructors modelling a sequence or a dict, and only in that order. Is that rule clear enough? > I believe that your proposal leads to an over-generalisation "call > arbitrary functions when handling parameter lists". I hope the above clears that up. It is as much about calling functions as ** is about raising kwargs to the power of. > 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. We dont strictly 'need' any language construct. Real men use assembler, right? >/ head, tuple(tail) = iterable /> In Python 3, that is spelled: head, *tail = iterable tail = tuple(tail) Yes, I know. How is that not a lot more verbose and worse than what I have proposed in all possible ways? > head, tail = somestring[0], somestring[1:] Well yes, splendid; we can do that with lists too since the dawn of Python. What you are saying here in effect is that you think the head/tail syntax is superfluous; that youd rather see it eliminated than generalized. > head, tail = next(mygenerator), mygenerator Which again of course works, but is yet again of entirely different form than any of the above solutions, while conceptually doing the same thing. Certainly, there is room for improved elegance here? -- http://mail.python.org/mailman/listinfo/python-list
Verbose and flexible args and kwargs syntax
On the contrary, it is a major point. You want us to change the language so you can program by Google. Sorry, aint't gonna happen. On the contrary; I believe I get to decide which points I consider important. This one, I do not. Sorry for putting it in the first paragraph. -- http://mail.python.org/mailman/listinfo/python-list
Verbose and flexible args and kwargs syntax
> On the contrary, it is a major point. Sorry, but im affraid it is up to ME to decide which point I feel are important. No, this is a minor point to me, and one that has been admirably put to rest by pointing out that spelling out the name of the symbol in google directly leads you to the information you are looking for. -- http://mail.python.org/mailman/listinfo/python-list