mirror of
https://github.com/jbranchaud/til
synced 2026-09-02 09:41:47 +00:00
Add Force Remaining Arguments To Be Named as a Python TIL
This commit is contained in:
@@ -10,7 +10,7 @@ working across different projects via [VisualMode](https://www.visualmode.dev/).
|
|||||||
|
|
||||||
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
||||||
|
|
||||||
_1827 TILs and counting..._
|
_1828 TILs and counting..._
|
||||||
|
|
||||||
See some of the other learning resources I work on:
|
See some of the other learning resources I work on:
|
||||||
|
|
||||||
@@ -1083,6 +1083,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Dunder Methods](python/dunder-methods.md)
|
- [Dunder Methods](python/dunder-methods.md)
|
||||||
- [Easy Key-Value Aggregates With defaultdict](python/easy-key-value-aggregates-with-defaultdict.md)
|
- [Easy Key-Value Aggregates With defaultdict](python/easy-key-value-aggregates-with-defaultdict.md)
|
||||||
- [Enable Pyright Type Checking In Cursor](python/enable-pyright-type-checking-in-cursor.md)
|
- [Enable Pyright Type Checking In Cursor](python/enable-pyright-type-checking-in-cursor.md)
|
||||||
|
- [Force Remaining Arguments To Be Named](python/force-remaining-arguments-to-be-named.md)
|
||||||
- [Get Absolute Seconds From `timedelta` Object](python/get-absolute-seconds-from-timedelta-object.md)
|
- [Get Absolute Seconds From `timedelta` Object](python/get-absolute-seconds-from-timedelta-object.md)
|
||||||
- [Get Quotient And Remainder In One Operation](python/get-quotient-and-remainder-in-one-operation.md)
|
- [Get Quotient And Remainder In One Operation](python/get-quotient-and-remainder-in-one-operation.md)
|
||||||
- [Globally Install CLI Tool With UV](python/globally-install-cli-tool-with-uv.md)
|
- [Globally Install CLI Tool With UV](python/globally-install-cli-tool-with-uv.md)
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# Force Remaining Arguments To Be Named
|
||||||
|
|
||||||
|
When the _positional argument collector_ (`*`) is used in a function definition,
|
||||||
|
all the arguments that follow it must now be explicitly named when invoking that
|
||||||
|
function. This is regardless of whether you are collecting positional arguments
|
||||||
|
into a named tuple (e.g. `*rest`) or are using the empty/dummy version (`*`).
|
||||||
|
|
||||||
|
A friend recently recommended I use this syntax to force some configuration
|
||||||
|
values (often booleans) to be explicitly named at call sites.
|
||||||
|
|
||||||
|
Here is an example of this in my [`py-vmt` project](https://github.com/jbranchaud/py-vmt):
|
||||||
|
|
||||||
|
```python
|
||||||
|
class CliContext:
|
||||||
|
def __init__(self, *, verbose: bool, repo: SessionRepository | None = None) -> None:
|
||||||
|
self.verbose: bool = verbose
|
||||||
|
self.active_session: Session | None = None
|
||||||
|
self.repo: SessionRepository = repo or JsonRepository()
|
||||||
|
self.active_session = self.repo.active_session()
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice that right after `self` is the `*` which means that both `verbose` and
|
||||||
|
`repo` must be named arguments.
|
||||||
|
|
||||||
|
Here is a corresponding call site:
|
||||||
|
|
||||||
|
```python
|
||||||
|
ctx.obj = CliContext(verbose=True)
|
||||||
|
```
|
||||||
|
|
||||||
|
Now when I initialize `CliContext`, there is no choice for me to pass in an
|
||||||
|
unnamed argument of `True`. It has to be paired with `verbose`. Above I've
|
||||||
|
excluded `repo` because that falls back to a default value. If I were to include
|
||||||
|
it, it would have to be named.
|
||||||
|
|
||||||
|
The same applies to this scenario where I'm collecting the positional arguments.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def build_identifier(first, *rest, delimiter="/"):
|
||||||
|
if rest is None:
|
||||||
|
return first
|
||||||
|
|
||||||
|
return delimiter.join([first, *rest])
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
>>> print(build_identifier("taco"))
|
||||||
|
taco
|
||||||
|
>>> print(build_identifier("taco", "bell", "mas", delimiter="-"))
|
||||||
|
taco-bell-mas
|
||||||
|
>>> print(build_identifier("taco", "bell", "mas", "-"))
|
||||||
|
taco/bell/mas/-
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice in the third example where I don't use a named argument for the
|
||||||
|
delimiter. It instead gets swept up in the collection of positional arguments.
|
||||||
|
|
||||||
|
This language of _positional argument collector_ I got from [Python in a
|
||||||
|
Nutshell, 4th
|
||||||
|
Edition](https://www.oreilly.com/library/view/python-in-a/9781098113544/) (see
|
||||||
|
pg. 96).
|
||||||
Reference in New Issue
Block a user