6 ms·
It is used when the number of argument can vary, like: def sum(*args: int) -> int: if len(args) == 0: return 0 return args[0] +
by Znafon 3y ago
It is used when the number of argument can vary, like:
def sum(*args: int) -> int:
if len(args) == 0:
return 0
return args[0] + sum(*args[1:])
- zoomablemind 3y agoIt seems altogether surprising that with an empty list or tuple a, a[1] results in index error, yet a[1:] quietly returns an empty list or tuple.
- hk__2 3y ago> It seems altogether surprising that with an empty list or tuple a, a[1] results in index error, yet a[1:] quietly returns an empty list or tuple. `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.
- macintux 3y agoThen why doesn’t a[1] return None? I understand the logic behind both decisions, but it’s not surprising that people find it inconsistent and unintuitive.
- hk__2 3y ago> Then why doesn’t a[1] return None? Because there would be no way to distinguish between "a[1] contains None" and "a[1]" doesn’t exist.
- macintux 3y agoAnd with a[1:] returning the empty list there’s no way to distinguish between a is empty and a only has one element. These are, in the end, relatively arbitrary language design decisions.
- akasakahakada 3y agoWhen you slice a list, you get a list. When you see there is nothing inside the returning list, you know that means end of list, contains zero element. Slicing and indexing return object at different level.
- macintux 3y agoSlicing a list, when the first index is invalid for that list, could easily throw an exception instead.
- zoomablemind 3y agoThis should signal an explicit error, which invalid index is indeed. If user believes for some reason the invalid indexing is ok, then it could be caught and handled. No ambiguity.
- Znafon 3y agoI think it is consistent, it works a bit like filtering an element from a mathematical set. 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).
- zoomablemind 3y agoBoth cases are an index error. It's just for some other reasons in case of the section, the error is represented by an empty object and it's left to user to handle the result. This could easily conceal the indexing error unless the caller code explicitly checks the length of the returned section.
- hk__2 3y ago> 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.
- zoomablemind 3y agoHere it is. It only underscores the ambiguity of such handling of the section indexes. Flagging the index error would make this less ambiguous/silent.
- js2 3y agoa[1] has to raise an IndexError because there's no return value it could use to otherwise communicate the item doesn't exist. Any such value could itself be a member of the sequence. To behave otherwise, Python would have to define a sentinel value that isn't allowed to be a member of a sequence. 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. https://discuss.python.org/t/why-isnt-slicing-out-of-range/ https://discuss.python.org/t/why-isnt-slicing-out-of-range/
- esafak 3y agoYou should use `Iterable`
- Znafon 3y agoI'm not sure 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.
- esafak 3y agoYour example has a fixed number of names. What if you wanted to accept any number of names, like Pablo Diego José Francisco de Paula Juan Nepomuceno María de los Remedios Cipriano de la Santísima Trinidad Ruiz y Picasso? Really, though, Iterables make more sense for monadic types.
- sdenton4 3y agoWe would force broad changes in human society to conform to the assumptions of our database scheme, same as we always have.
- thaumasiotes 3y agoI knew a Chinese girl whose parents, surnamed 吕 and 郎, wanted to give her the combined surname 吕郎. This was not allowed, so formally she was surnamed 吕 and given a three-syllable personal name starting with 郎. 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.
- ddejohn 3y agoThat is an entirely different use-case than a function signature allowing arbitrary keyword arguments. Arbitrary keyword args are different than arbitrary positional args like you have in your example. 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.**