Positional-only and keyword-only arguments in Python
Vložit
- čas přidán 4. 06. 2024
- Make function args positional or keyword-only.
In Python, it's possible to force a function argument to be positional-only or keyword-only. In this video, we see the syntax for doing this, as well as see some examples and reasons for why you might want to actually make a parameter positional-only or keyword-only.
Note: positional-only arguments are a Python 3.8+ feature. Keyword-only are Python 3.0+.
Errata:
1. At 1:22 you'll get a TypeError, not a SyntaxError.
― mCoding with James Murphy (mcoding.io)
Source code: github.com/mCodingLLC/VideosS...
Positional-only PEP: peps.python.org/pep-0570/
Keyword-only PEP: peps.python.org/pep-3102/
SUPPORT ME ⭐
---------------------------------------------------
Patreon: / mcoding
Paypal: www.paypal.com/donate/?hosted...
Other donations: mcoding.io/donate
Top patrons and donors: Jameson, Laura M, Dragos C, Vahnekie, John Martin, Casey G
BE ACTIVE IN MY COMMUNITY 😄
---------------------------------------------------
Discord: / discord
Github: github.com/mCodingLLC/
Reddit: / mcoding
Facebook: / james.mcoding
CHAPTERS
---------------------------------------------------
0:00 Intro
1:08 Keyword-only arguments
4:50 Positional-only arguments
7:45 Uncommon to use both
8:29 Speed test, position args are faster - Věda a technologie
Every video you drop is so hugely important. Youre single handedly saving my in-production code from ignorance
I take full credit! Unless anything goes wrong, then you did it all on your own!
Yes! I think the same about it!
@@mCoding Sounds like my boss.
Thanks; and I`m glad You`re happy.
@@mCoding I think Trump stole your quote lol.
Wow. On other channels this video would just have been the display of the syntax and some code examples. But as always, you share valuable knowledge in the form of use cases, benchmarking, 'tricks' to remember the syntax, etc. I yearn to one day be as good of an educator as you. Thanks for the video!
What I love about these videos is that each highlights one specific topic that you rarely see anywhere else, yet all of them have real world applications. Thank you James
Thanks for the support!
That explanation was CLEAN! And the speed test was the icing on the cake! Thank you so much
Glad you enjoyed! I hope you find many other desserts on my channel.
When the positional only stuff came out, I also remember hearing that there were some reasons related to the C foreign function interface. Most other languages don’t have kwargs, and this (supposedly) helped maintain symmetry when you were defining wrappers for C functions
That would make sense, the default for wrapping a function in a language that doesn't have kwargs makes sense to be positional only.
Yeah, there have been positional-only built-ins forever, so when Argument Clinic was implemented, it supported them and the use of "/" (the "inverse" of "*") was adopted there. Then people started asking if they could write pure-Python functions with the same APIs as those in the built-ins, and the "/" was added to Python itself.
That doesn’t make any sense. Keyword arguments allow Python to rearrange the arguments into the right order to pass to a lower-level function. The fact that the lower-level function is written in a language that doesn’t support keyword arguments is irrelevant, and no excuse for the higher-level language to limit itself.
@@lawrencedoliveiro9104 Well, Python didn't always have keyword arguments (I can't recall, but maybe added in 1.4 or 1.5?). At the time, creating keyword argument lists in the interpreter was quite expensive, so the already-existing builtins were left as positional-only, and that has been carried through history.
@@d00dEEE Many existing functions have had keyword arguments added. By its nature, it doesn’t break backward compatibility.
One use-case I've heard for positional-only args is that it allows you to have a truly-general kwargs parameter.
Like, say you had a function that lets you modify some sort of general-purpose configuration settings, and it needs to take two things as input: a section to put the settings in, and some key-value pairs for what settings to change. The definition could look like:
def modify_config(section, **changes):
...
and you'd then call this like:
modify_config("subscriptions", mCoding=True)
But what if you wanted to have a setting that is literally called "section"? You can't call:
modify_coding("a thing", section="left")
because it will treat the "section=" parameter as being the first arg to the function, not a part of the kwargs, and you'll get an error that you're providing two values for the same argument.
So our function isn't completely general-purpose, we can't use it to change a setting that's called "section".
However, what if we change that parameter to be positional-only?
def modify_config(section, /, **changes):
...
modify_config("a thing", section="left")
Now, the call works properly, exactly as we'd expect it, and the section="left" parameter ends up in the kwargs.
While your example works, I can’t help feeling it’s a little strained.
@@lawrencedoliveiro9104 strained how if may ask?
This is exactly what the dict() function does.(Even before the feature was added to the language, it was implemented as a special case in C)
In fact this is how Pablo Galindo Salgado justified the modification. The other option, let your function swallow everything, would have imply a horrible documentation. In addition this feature was already in use in the insights of the standard library. It just has become available for the Python users.
As a fun fact the usage of the bar let the standard library implementation to be reduced in 3,000 lines.
Another engaging and informative video with a pleasantly narrow scope 🤠
Glad you enjoyed it!
I recommend your videos all the time. The depth on a narrow topic is exactly the type of video I've been after lately. You dont just explain what it does and some examples, you show exactly how something works and you somehow do it concisely.
I learned an additional thing from this, as I didn't know about the {var_name=} feature of f-strings, so thank you for that as well!
This is the most clear and concise explanation and how-to tutorial on python arguments I have seen. Excellent job. Bravo!
Great video. I recently came across your videos and have been gobbling them up and passing them along to my coworkers. Thank you so much for doing this and I really appreciate the nicely digestible length of your videos yum yum.
Haha gobble gobble. Enjoy! Glad you like my videos.
Thank you so much. I've been wondering about the slash in function parameters for so long
This has been in python since 3.0 and I never knew what it meant (have not seen it in many codebases with the exception of boto3 stubs) thanks for this!
You always provide a new (deeper) perspective on seemingly simple concepts. Im glad I found your channel, you have the best content Ive seen on YT.
Great to hear, your views are appreciated!
one of the best explanation (about args and kwargs) i've ever heard
I learned something new today. Thanks for making this video!
I always learn something new from your videos, thank you!
I learned this from the book “90 Specific Ways to Write Better Python”. It’s such a great book that I would recommend to anyone looking to become a more professional Python developer
wow, just started learning about this. You're amazing, James.
Very welcome and thanks for watching!
Damn, man these videos are what I wanted, one the edge python cases/implementation or advanced video.
Banging video. Learnt something new, seems advanced but simple to understand and use. Love it
Had never known about this syntax, but I can think of some good usecases allready! Your video's are really the best for learning these obscure but very often usefull features you don't see in beginners courses.
Note that int.__pow__ (and maybe other number types) has "mod" parameter especially for cases "(x ** y) % mod"
Good catch! Thanks for pointing this out.
Amazing video. I've actually never seen this feature used before but I feel like it should be best practice, especially when writing APIs
Times I refactor my code before finding your channel = once, times I refactor my code after finding your channel = once a day
Such a useful video I wondered how to do this exact case yesterday by chance!!
Awesome video! I like the def foo(*, arg_1, arg_2, arg_3=default_3, ...): pattern to force users to explicitly pass in keyword names. This is useful for methods that have a lot of inputs to a) force users to look up the signature so they see everything that they need to pass and are able to pass in and b) ensure no parameter mix ups occur. This approach also makes code a bit more explicit which can be helpful. Of course it's more verbose which could be seen as a downside.
It would be nice to see examples where you include default arguments as well. When I first learned about these I was confused by the fact that there was a difference between keyword only args and optional args (before I erroneously thought they were one and the same). I also think there's a confusing case of: Can I have position-only args with and without defaults while also having keyword-only args with and without defaults?
I don't really need to see examples where there are explicitly positional or keyword args because I feel like those cases are just confusing, and like you helpfully pointed out, not really useful.
I do have to say that I've hesitated to put these patterns in much of my code though, because I believe it's python 3.9+ and at the time I learned it I was still working with lower versions of python. I also hesitate to put it in because I think most people don't know what it means and it would surprise them.
The positional-only feature is recent, but the "/" syntax has been used in the built-in functions' documentation for a long time
Very interesting insights
Thank you for that video!
This is EXACTLY what I need today!
I worked with a (proprietary) PHP framework which had an approach of making as few args as possible mandatory, and as many parameters of an operation args with sensible defaults. The "keyword arguments" was the way it was implemented - you'd often have a function with 15 args, one required, the rest - as needed. It was very friendly in use that way - bare minimum to get it to work, easy to change whatever you want changed.
Your channel booted up my python skills x10 🥂
So good. Never heard about it the pure * before and directly implemented it in my code
Loved the "yum"! Also, James, where is your face? It was so nice to see you narrating the video :)
Great work. Really appreciate your efforts.
Amazing stuff as always my good man
great explanation! thanks!!
Congrats on the 100k
Thank you so much 😀
Oh that looks great! I have to use it in the library I'm writing
Wonderful! Great as always
5:05 best part!
0:40 jfyi for the completionist
foo(2, a=1, c=3) is a TypeError
foo() got multiple values for argument 'a'
This was super informative. I understand a little better how to use *args and **kwargs which I know wasn't the point of this video. But still, this was very useful. Thank you!
superb explanation
I never knew about plain *, it makes total sense.
Very helpful !😀
Great videos! ✌
Could you do an in-depth video on asyncio?
By in-depth I mean how it works under the hood; Particularly how it compares to & differs from multithreading, how does python know when to "wait for this to finish and run some other code in the meantime" and what happens under the hood when the results are ready and how it relates to OS scheduling and sleep queue.
So basically, content that you find on this channel that it's harder to find elsewhere.
This has been on my list for a long time!
Lukasz Langa had made a series of videos if you really want a deep dive into asyncio: czcams.com/play/PLhNSoGM2ik6SIkVGXWBwerucXjgP1rHmB.html
Star is like star-args but without the args 🤣 mCoding is like m but with Coding 😄 Your content is so advanced, I love it! 👌
This is GOLD!
Awesome! Props to you.
Great and interesting video
The benchmark at the end was the icing on the cake. Is there a performance change? Not enough to bother, but at least we know that
I've defined keyword-only parameters before, but I honestly had no idea positional-only existed. Doubt I'll find much use for it, but good to know.
thanks for the video
My takeaway:
star yum
star star yum yum
slash NO NAME FOR YOU
Great vid !
Great content once more!
I somehow have never see this syntax. I've seen mentions of this while manipulating python ASTs but I didn't know what they really meant lol
@@mrdkaaa you read the docs? nerd
What does ASTs mean?
@@pranavnyavanandi9710 abstract syntax tree, basically I was modding python to make creating and manipulating lambdas easier lol
Amazing!
Thanks James, great video. In what python version of python was this added?
Keyword-only arguments were introduced in 3.0.
positional only was 3.8
OMG, I had to have a “dummy” parameter as the first argument because I couldn’t find a simple way to force all parameters to be named. Never found this syntax of just star-comma offered as a solution. It’s quite logical to remember that it’s like “*args” without the argument name. As if it just doesn’t give anywhere for the positional args to go.
This I find helpful when there're a lot of boolean args, which if passed without keywords, would make its invocation harder to understand -- e.g. `process_two_numbers(3, 5, True, True, False, None, True)` -- no idea what's happening here without forced kwargs :)
Never seen this before. So cool. I wonder why positional only is faster than keyword. Thought it would be backwards
I think its because keyword arguments are stored as a dict and positional arguments are a tuple. A dict is a considerably more expensive data structure.
Is power mod slow because you could also implement binary exponentiation together with taking the mod on the output on each iteration?
Yes exactly, fast pow and take mod n each iteration will be much much faster then computing a huge exponentiation then reducing mod n.
4:00 this is also why most projects should probably use mypy and type annotations :)
4:35 Buying 10,000 items of $4,500 each, costs as much as buying 4,500 items of $10,000 each.
Unless you're the seller :)
I think you'll find the buyer would be much happier to receive 10000 units rather than 4500 units for the same price! (Assuming there aren't any crazy storage costs, minimum holding times, or other penalties incurred for holding units).
@@mCoding These are no bugs, just happy mistakes.
I’ve actually used this before without really knowing what it was doing while making a discord bot
Until now I haven't used this feature a lot because I don't want to put restrictions on the users of my code. However, I make most boolean arguments keyword-only, because when passed as a literal it's usually not clear from reading the code what the argument is supposed to mean.
4:58. If you want to swallow up keyword args you can just use **kwargs. This isn't exactly a parallel to / but is the equivalent kwargs version of *args
Pretty interesting
thanks for the good content
You are very welcome, glad you enjoyed!
@@mCoding in my IDE I have an extension that pre-writes docstrings for me, based on the parsing of the function body and signature, but it does not capture * and / in this context. I made a feature request ;)
I think I finally remember the syntax... the / * is really hard to remember
How did you run into all this information?
I consider myself to be a reasonably experienced Python dev and I swear, 75% of your videos I come away learning something that I can actually use in my day-to-day work in a way that makes my output unquestionably better.
What can I do to rapidly pick up info like this?
books: fluent python and python cookbook taught me soo much about python that I'd probably not have learned anywhere else
reading library code really helps. especially libraries that were written by well known python core devs very recently. good examples would be fastapi for example, you'll learn a whole lot about type annotations
lastly, python's own tutorial covers pretty much every language feature. I take a look at it every few months
fluent python has a 2nd edition coming out in May, that's going to be one of the best Python resources for a while
@@sadhlife I just started using FastAPI so that would be especially relevant. I've read a few libraries code before but that was just because they were very poorly documented and I was trying to figure out how to do something. Reading through on well-documented libraries seems like a good idea.
Thanks!
I love your videos ❤️
Thanks so much!
Saw this some weeks ago in a colleagues Code.
I always wanted to know whataheck that * meant on the others code... dam.. thank you.. that was greatly useful!
"We don't need x."
I feel attacked lmao
Jokes aside, this has been an awesome watch with some immediate gains in my codebases 🥰
I've always wondered what **kwargs means but never bothered to look up. Thanks!
The best part of this is f"{x=}" I didnt know you could do that
My usual examples for why you would want keyword/positional-only arguments are:
Keyword Only: consider n_sorted(data, true) -- what does the 'true' set there? ascending/descending? nulls first/last? Maybe something else? What if you would find n_sorted(data, false, true) -- which true and false is which? is the first false only there to keep the second argument as default to reach the third positional argument? n_sorted(data, nulls_last=True) is unambiguous about that.
Positional only: Reason to enforce positional order could be if the ability to change the order would only exist to mess with the person reading the code. Similar to your example, divide(y=2, x=3) or Fraction(denominator=2, numerator=3) would seem to be only there to obfuscate that this is 3/2 and not 2/3
But why not just leave the caller the option? In the first case, they can still use keyword arguments if they feel like the ambiguity might be a problem. Same thing in the 2nd example. If the caller decides to swap the argument order, they probably had a good reason for it.
Basically, you are trying to force the person using your code to do what you think is best for them. But by doing so, you are blocking off use-cases you might not have thought about.
Keyword-only arguments can be useful where you think you might add more later, and maybe change the order.
There is one situation where there is a specific use for them: normally once you specify a default value for a formal argument, all remaining ones must also have defaults. But in the keyword-only section, this rule no longer applies, and you can omit the default for an arg that comes after one that has a default.
7:22 Your note about slow function, what would be faster equivalent?
In the algorithm to compute pow, which is typically some kind of repeated squaring algorithm, take mod n each step instead of at the end. The builtin pow function also takes a mod parametee that does this.
7:43 I actually recently used that in my project lol
You should be able to put the star next to the slash if you don't need the middle
This is not related to the video but since there are probably many python expert here I'll ask my question. Can I have some tips/good practices about how to create and organize a python package. Also what should be favored, relative or absolute imports? I prefer absolute because theye are easy to copy paste between files.
you love to see it
I never knew about the '/' and '*' in the function parameter list - they are awesome.
Also, I realised that I can cheat the "slap the like button an odd number of times" system by hitting it twice, but also clicking dislike once in between. Under the cost of the emotional baring of having your video disliked for a moment this still results in a like ;)
I love it. I want to feed the YT algorithm so I make this comment.
I have rhe impression you are probably resonably decent at writing python code :-)
Yeah boi!
How does this work w partial application?
great vid as always
btw discord gang 🤙🤙
the video is 9 minutes long and only uploaded 2 minutes ago 🤔
4x speed?
@@jacanchaplais8083 I had access to it before publication as a moderator
@@trag1czny fair haha
Thank you for your loyal viewing!
What is the "good practice" way of implementing keyword arguments with default values?
something like
def f(x=None):
if x is None:
x = smth
That is unless you also plan to allow for None as a valid value, then it's a bit more complicated
@@user-xh9pu2wj6b So it's actually the same as for a positional argument? What I am doing now is to have a default dictionary, I loop through its keys, if the key is in kwargs.keys(), I replace the default value with kwargs[key]. This feels... too javascripty, i don't know.
The reason I prefer something like this that I would like to have a function taking an arbitrary kwargs dictionary with an arbitrary default value dictionary.
@@AsgerJon oh, in case of multiple defaults in a dictionary like that, I think it's a fine approach. I code in TS/JS a lot, so I don't see any real problem there)
Another way to do it is to use an update method of a dictionary and pass kwargs in it.
You'll have something like:
def f (**kwargs):
kvals={"x": 1, "y": 2}
kvals.update(kwargs)
This will essentially merge the two dicts with overwrites, so if some key was only in kvals, it'll stay there with default value. If it's in both dicts, the value will come from kwargs.
And I think it might be faster than looping by hand, but I never measured the performance.
@@user-xh9pu2wj6b Speed is no concern ever in Python. If part of your code for real causes speed issues, then numba.jit and possibly even cuda jit.
Here's what I'll do: I will subclass the default dictionary, into one that does as you suggest, but then I will put it in the __add__ method. Like:
self.defVals = {...}
self.defVals += kwargs
BOOM! Python all the way!
I now very much want to know how to make a Python3-Thinter-to-HTML5 app far as it can get... because I very much struggle many thousands of times more with every other programming language despite the 6 years I tried. Granted... p5js has recently got my attention, but... it still looks a bit overly complicated to re-edit which I accomplished very much the same graphics which is too slow and doesn't transfer to Android via fully* the SD card. Unfortunately... I can't even find an entire side-by-side syntax comparison.
`mCoding` seems like A/M`tion; similar to `Playwright`.
U can memorize /* which start multiline comment in if I remember correct.
You are welcome! : )
This isn't really important but..
10,000x4500 and 4500x10,000 are the same since multiplication is commutative.
Awesome video as always though!
Wouldn’t it make sense from an enterprise standpoint that all arguments are passed as keywords? Otherwise the reader has to reference the functions implementation or comments if it has them to understand what the parameters mean.
damn I envy people who can work with python.
I work on an ancient mutated php codebase.
I recently found some functions with a messy signsture and a bunch of option paramters.
That kind of stuff is just bad code in php.
In python that might work If I used the method to force those arguments to be keyword only.
(in other places the codebase expects (what php calls) an "array" with keyword=>value pairs wich basically simulates keyword only args.
fun times.
6:24 How about “truthvalue” or “flag”. Or even “colbert”.
yum
Im sad I didn't read this before attempting to code a classless version of Blackjack.
I feel like you had every opportunity to come up with a weird use case for the use of all three options
Il y a grep sur Windows?
WSL
Good video as always ! Not really conviced by the use of positional args only though.