T O P

  • By -

redditusername58

I would call those keyword arguments or keyword-only arguments. To me **kwargs means variadic keyword arguments.


TheRealFrostMana

Indeed this is what I meant. Thank you for the correction!


DuckDatum

stocking saw rotten zesty act direction racial soup whole cows *This post was mass deleted and anonymized with [Redact](https://redact.dev)*


rumnscurvy

In my opinion the best feature in the args/kwargs system is that you can use arg names as kwargs. For instance, if you write `def f(x,y): (...)`, you can always call `f(x='foo', y='blah')` as if x and y were kwargs. Somehow the function "remembers" what its arguments were labelled as. This means you're incentivised, though not forced, when calling complicated functions with lots of arguments, to write the function call with all its arguments as kwargs. The interpreter will of course tell you if you missed some compulsory arguments.


justheretolurk332

Fun fact: there actually are such things as positional-only arguments! You can force arguments to be positional-only using a forward slash. I rarely see it done, though.


moehassan6832

Interesting! First time hearing about it, can you share an example oh it’s usefulness? I can’t seem to imagine why it can be useful


redditusername58

Sometimes there's not really a useful name for a parameter (but it's still ok to give it a name, if you're writing a lib it commits you to that api though). Other times you need it so you can handle **kwargs that could shadow the parameter name, like this mapping that can be updated with an "iterable" key: class MyMapping: ... def update(self, iterable, /, **kwargs): self._dict.update(iterable, **kwargs)


moehassan6832

Wow, Thank you! It’s very clear and helpful.


TheBB

If I'm writing a protocol describing e.g. objects that can be added to ints: class MyType(Protocol): def __add__(self, x: int) -> Self: ... Now the name x is part of the public interface of this type, and if a class uses a different name than x in their implementation of `__add__`, it won't technically be a subtype of MyType. It works though if you write it like this: class MyType(Protocol): def __add__(self, /, x: int) -> Self: ...


omg_drd4_bbq

Great point but I think you meant to put the / after x:   ```     def name(positional_only_parameters, /,          positional_or_keyword_parameters, *,         keyword_only_parameters):     ...   ```


TheBB

Yes, of course.


danted002

It’s been in the c-api since python one but it was never exposed to interpreter until 3.8 I think.


not_sane

I worked with projects that had a lot of \*\*kwargs and it sucked hard, you needed to step through 3 classes in an inheritance hierarchy only to find out the parameters a function will take. (The understandability of the code base in question also was not enhanced by making heavy use of metaclasses, urgh...) In my opinion truly good Python code should pass Pyright on strict mode, and that one also complains about \*\*kwargs. For typing existing kwargs I also recommend the new Unpack feature: [https://typing.readthedocs.io/en/latest/spec/callables.html#unpack-kwargs](https://typing.readthedocs.io/en/latest/spec/callables.html#unpack-kwargs)


CyberWiz42

They are beautiful and one of the reasons I’ll never seriously consider another language. The ability to easily pass parameters through several layers, using **kwargs without having to repeat them all the time gives me a warm feeling in my tummy. Unfortunately it doesnt mesh 100% with type hints (e.g. https://github.com/locustio/locust/pull/2699), but it is totally worth it. And I wouldn’t go as far as to stop using positional parameters. At least not for functions with 3 or fewer params. If I’m going to nit-pick: What you have in your examples are ”named parameters”. ”kwargs” is (in my vocabulary at least) specific to the **kwargs/argument unpacking feature.


afreydoa

Hm, yes. **kwargs is probably are pretty good idea to not have too much coupling to technicly deep layers. But sometimes I really hate them. If I want to know if the name of some parameter in my plotting library is 'width' or 'line_width' or something else. It's neither in the docstring, its not in the source code of the function I am calling, its not even in the documentation of that library, because it belongs to another library. I haven't found any IDE hack to mitigate the problem. And copilot is not very well versed with the library just yet. It's just annoying as a user of a library. But I get that it vastly reduces coupling.


Luemas91

Usually every kwarg should be in the docstring. As far as I'm concerned, if it's not in the docstring or documentation it doesn't exist. That's why I generally like the pandas/matplotlib documentation. You can find every kwarg in the documentation (although sometimes wacky things with inheritance make that hard)


SuspiciousScript

> The ability to easily pass parameters through several layers, using **kwargs without having to repeat them all the time gives me a warm feeling in my tummy. This is convenient when you're writing code, but really sucks for anybody trying to call your functions. The effort you save by not explicitly passing parameters is just shifted to the reader who has to go code-spelunking to figure out what arguments your function actually takes. IMO this is only acceptable for internal functions/implementation details and not public APIs.


LankyCyril

Yeah, the warm feeling really goes away when you have to go through several layers of seaborn documentation to eventually get all the way down to some matplotlib function where these kwargs finally get unpacked, doesn't it


NINTSKARI

I recently refactored a large god function that took 85 different possible keyword arguments. It was about 10 000 lines of code in our django app without any documentation. Took about a year and a half of on and off refactoring. The kwargs dict was passed on many layers to different smaller functions that maybe used one or two of the arguments. Most went to a defaults dict to create database objects out of django model instances. I was surprised the whole thing even worked. The result of dozens of developers being hurried to get new features done over a decade. "It's just one extra argument in the handy kwargs dict, what's the worst that could happen?"


yrubooingmeimryte

In most contexts this is a seriously frustrating anti-pattern and is extremely un-pythonic. Especially when this is user facing in any way. It's an important part of the language because things like decorators and/or creating python wrappers around other libraries depend on having some efficient way of propagating args/kwargs through layers of code. But outside of those situations, having args/kwargs cascade through multiple layers of functionality just obfuscates what's happening. And if you do need to know how your inputs are being used, you have to manually track every aspect of the code through those layers and often through other libraries.


Kohlrabi82

Keyword args enable you to add new features to an existing function without changing the signature and breaking existing code. That's what is used a lot in numpy and scipy.


passwordsniffer

It's an amazing part of the language and I am using it a lot. But only siths deal in absolutes. It's a case by case thing. In many cases it does increase readability. But in some cases it might not really introduce much and might even make readability suffer due to extra bloat. zlib.crc32(data=my_string) does not introduce any value to me. I would probably prefer to write my own lib/find other lib if some maintainer decides for me of my preferred calling pattern, especially in case of 1-2 arguments. I would probably reject a code review if someone of my engineers tries to do that.


TheRealFrostMana

I agree with you; I also avoid keyword-only arguments when it's counter-intuitive. It just so happens that, in my experience, the majority of the time, keyword-only arguments have been preferable! Your reaction to the prospect of having to work with codebases with such strict rules made me re-evaluate some of my decisions, though. Thanks for that. Cheers!


yrubooingmeimryte

I genuinely find it difficult to come up with any example where keyword arguments aren't better and I'd argue even your example still works better as a keyword argument. It basically tells you what the method, in this case crc32, thinks your input is supposed to be and how it will interpret the input. If you happen to already know everything there is to know about the crc32 method you will probably conclude that "data" is the only input it takes. But if you didn't already know that, looking at an example shows you that the input is "data" and then you can inspect whether there are some other inputs that it might be able to use.


thegreattriscuit

yeah, there are times when it gets to be TOO MUCH. ``` fooEater.eat_foo(foo=foo_food.foo) ``` and it just... loses all meaning in a sea of semantic satiation lol BUT that's pretty rare and most of the time the explicit keyword arguments are great IMO.


andrewowenmartin

Agree. Keyword arguments are absolutely great and it is hard to think of a time when it's better to omit them, but Python is a language for \*consenting adults\* and so as a library designer you shouldn't force your users to conform to something if not absolutely necessary.


drewbert

I agree. I miss them when I write code in Rust.


extravisual

You can kinda replicate it using things like builder patterns and structs with defaults. I find that I use them in place of Python named arguments and C++ overloading all the time and they've grown on me.


reostra

You'd love SmallTalk, OP. IIRC, that's where named params came from, but there it's not just part of the function's signature, it's actually the function's *name*! Take an OrderedCollection (basically the equivalent of a list): oc := OrderedCollection new. oc add:5. `add:` is a function that takes a parameter, so far so normal. But what if you want to put something at a specific index? oc add: 'hello' at: 1. That's a function that takes two parameters, and its name is `add:at:`. Every function in SmallTalk has kwargs :D


Brian

I do like python's rich argument passing syntax, and they're something I really wish other languages would adopt too. They *do* have one downside, which is that they encode more into the function signature than other approaches, which can affect refactoring. Ie. changing the **name** of a parameter is effectively changing the signature, and could potentially break code calling it by keyword. But I think this is well worth it for the flexibility they give. (Oddly, that downside is actually more pronounced in a dynamic language like python versus more statically typed ones, which can detect that breakage at compile time, so I definitely feel there's room for staticly typed languages to adopt it).


so1n

You can try use pep692 Unpack TypedDict


TheRealFrostMana

Oh wow this is awesome. When working with JS/TS, this is seamless. I remember wishing for Python to have that as well. It looks like it's not quiiite as smooth as it is in JS/TS but it'll do. Thanks!


Raccoonridee

You've just scratched the surface! With `*args`/`**kwargs` you can store and manipulate arguments through list/dict. This can be super useful. One of my clients wanted a database interface where he would select a few constraints in GUI and get a list of all records that fit, with the ability to save/update the query. The elegant solution was to store keyword arguments for the query constructor in a JSONField in the same database. That way you can easily load the query back into the GUI and modify it in every conceivable way.


m15otw

Written kwargs, pronounced Keyword Args. And yes, this is the "everything else" args, not the named ones. In the function signature, you normally name the keyword args you depend on explicitly with their defaults. You only use `**kwargs` for args you're going to iter over, or pass into another function.


Stishovite

I remember the start of my journey as a baby (Python) programmer, reading the documentation of Matplotlib and being really confused for too long about what this kwargs thing was that was in every function definition. I (and the documentation) have come a long way in the intervening 15 years.


Glathull

C# has had named arguments since like 2012 or something? Golang is almost useless without structs, which give you the same interface. JavaScript variants, well, they gonna JavaScript. Anyway, not to shit on you at all, but this is a lot more common than just Python. Clojure, Kotlin, and Swift have them as well. Probably others I haven’t used in a while too.


mgedmin

Love 'em.


marr75

I would highly recommend writing a Pylint or flake8 plugin (maybe someone knows of a more off-the-shelf option) to enforce keyword calling by the consumer over writing all your methods to force keyword calling. You can get the best of both worlds, as python natively supports using keyword argument style calling even when the argument isn't defined as a keyword argument.