On Thu, Dec 02, 2021 at 01:20:27PM -0800, abed...@gmail.com wrote:
If you want the parameter to default to an empty list, it's categorically more explicit to have the parameter default to an empty list.
You've gone from talking about *my* intentions, which you got wrong, to an argument about which is "more explicit".
In the simple example of the default being a new empty list:
# Using Chris' preferred syntax, not mine def func(arg=>):
then I agree: once you know what the syntax means, then it is more explicit at telling the reader that the default value is an empty list. Great! This sort of thing is the primary use-case of the feature.
But let's talk about more complex examples:
def open(filename, mode='r', buffering=-1): ...
How would you make that "more explicit"?
def open(filename, mode='r', buffering=>( 1 if 'b' not in mode and os.fdopen(os.open(filename)).isatty() else _guess_system_blocksize() or io.DEFAULT_BUFFER_SIZE ) ): ...
Too much information! We're now drowning in explicitness.
Now how do I, the caller, *explicitly* indicate that I want to use that system-dependent value? I just want a nice, simple value I can explicitly pass as buffering to say "just use the default".
with open('myfile.txt', buffering= what? ) as f:
I can't. So in this case, your agonisingly explicit default expression forces the caller to be *less* explicit when they call the function.
What the right hand giveth, the left hand taketh away.
Can we agree that, like salt, sugar, and bike-shedding, sometimes you can have *too much* explicitness in code? Sometimes the right level of explicitness is to have an agreed upon symbol that acts as a short, easy to read and write, documented and explicit signal to the function "give me the default value".
And that symbol can be -1, or an enumeration, or a string, or None.
This is not a hack, and its not "implicit".
None of my comment had anything to do with the caller's perspective.
The caller's perspective is important. The caller has to read the function signature (either in the documentation, or if they use `help(function)` in the interpreter, or when their IDE offers up tooltips or argument completion). The caller has to actually use the function. We should consider their perspective.
If my intent is that I want a parameter to default to an empty list, I wouldn't assign it to an object called "monkey_pants" by default then add code to the body of the function to check if it's "monkey_pants".
Funny you should say that, but *totally by coincidence*, the Bulgarian word for "default" happens to be transliterated into English as *monkeypants*, so if I were Bulgarian that is exactly what I might do! How weird is that?
Nah, I'm kidding of course. But the point I am making is that you are mocking the concept by using a totally silly example. "monkey_pants" indeed, ha ha how very droll. But if you used a more meaningful symbol, like "default", or some enumeration with a meaningful name, or a value which is a standard idiom such as -1, then the idea isn't so ridiculous.
And None is one such standard idiom.
*Especially* when the default value is not some trivially simple expression such as an empty list, but a more complicated expression such as the default buffering used by open files, or in my earlier example of the default collation (a sequence of letters which depends on the other input arguments).
Steven D'Aprano "How is it misleading?"
Your way of having a parameter default to an empty list (or whatever) is by having the parameter default to None. That's how it's misleading.
All you have done is repeat that it is misleading. I'm still no clearer why you think it is misleading to document "if the argument is missing or None, the default behaviour is ...".
Is the documentation false? Does the function not do exactly what it says it will do if you pass that symbol?
Let's be more concrete.
Do you feel that using -1 for the buffer size in open() is "misleading"? Do you think that there is ever a possibility that someday Python's file I/O will use a buffer with *literally* a size of -1?