def sum(*args: int) -> int:
if len(args) == 0:
return 0
return args[0] + sum(*args[1:]) def sum(*args: int) -> int:
if len(args) == 0:
return 0
return args[0] + sum(*args[1:])GP is suggesting that one should only ever use explicit keyword-only args (anything listed after `*,` in the signature) versus arbitrary keyword args implicit via `**kwargs`.
e.g. (omitting type hints for clarity):
def sum(*args, **arbitrary_kwargs):
...
vs def sum(*args, some_keyword_only_arg):
...
In my opinion if one finds themselves writing code that uses arbitrary kwargs, they've got a design problem.**`a[1:]` returns the sequence of elements that start at index 1. If there is no such element, the list is empty. I don’t see any good reason why this should throw an error.
I understand the logic behind both decisions, but it’s not surprising that people find it inconsistent and unintuitive.
Because there would be no way to distinguish between "a[1] contains None" and "a[1]" doesn’t exist.
These are, in the end, relatively arbitrary language design decisions.
Given a set of sheeps, let x be the five-legged sheep is inconsistent because we know neither the existence or uniqueness of shuch sheep, so it raises an exception.
Given a set of sheeps, let x be the subset of five legged sheeps is the empty set because there is no such sheep.
but this may also just be because I internalised Python's behavior.
Some language have a specific value to denote the first thing, for example:
["a", "b", "c"][4]
gives `undefined` in JavaScript but it differs from `null` which would be the equivalent to `None` in Python (and I don't think Python has such concept).This could easily conceal the indexing error unless the caller code explicitly checks the length of the returned section.
An empty returned section doesn’t mean the index was out of bounds (`a[0:0]`); if you want to make sure you have to check the length before slicing, like in Go.
When using slice notation, the return value is a sequence, so returning a zero-length sequence is sufficient to communicate you asked for more items than exist.
It may be surprising, but it almost always leads to more ergonomic code.
print(firstname, lastname)
for example is more readable than print((firstname, lastname))
especially since I would then have to write print((surname,))
to just print a single string.Variadic functions are rather classic, I think Go, Rust, C and JavaScript also have them.
There are a couple funny things about this:
1. A personal name of three syllables is stranger than a surname of two.
2. Double-syllable surnames are unusual, but definitely not unheard of. This girl told me that she hadn't been allowed to receive the double surname 吕郎, because it was too long. I asked what would have happened if her double surname had been 司马 instead. "That's different!"
(If the government of China tried to pick a legitimacy fight with the name 司马, it would lose, and everyone knows this.)
So this almost looks like an example of the kind of thing you're referring to, except that the database scheme has nothing to do with it. A surname that was nontraditional but within the technical norms was rejected in favor of a personal name that was both nontraditional and well outside the technical norms.
What do you do with your first example if you have a list (generated at runtime, not a static one) to pass to the function? This wouldn't work (imagine the first line is more complicated):
l = (1,2,3)
print(l)Something I keep relearning is that people are different, sometimes in ways hard for me to comprehend :)
xs = (1, 2, 3)
f(*xs)
is equivalent to f(1, 2, 3), not f((1, 2, 3))