Repository navigation
Allow default keyword argument in dict.get() method #124675
Description
Activity
- addedtype-featureA feature request or enhancementA feature request or enhancement
on Sep 27, 2024 This change aligns with PEP 20 (The Zen of Python), specifically the principle "Explicit is better than implicit." Using a keyword argument makes the intention clearer, especially when the default value is complex or when the method call is part of a larger expression
Yes but there is also "Although practicality beats purity." and "There should be one-- and preferably only one --obvious way to do it.". So, I wouldn't take the Zen as the holy scriptures in this case.
Many Python built-in functions and methods allow both positional and keyword arguments for optional parameters (e.g., sorted(iterable, key=None, reverse=False)). This change would bring dict.get() in line with this common pattern.
Changing
dict.getshould also warrant a change onnext()since this is the same interface for a similar purpose. More generally, I think we need to consider all similar cases instead of changing a specific one (I don't know if there are more).sortedis a bit different thandict.getbecause it has two optional arguments, so if one only needsreversebut notkey, it is better to only supplyreversewithout explicitly passingNonetokey. Other examples that you didn't cite aremaxandminbut this is only because they accept a variadic number of arguments.This change would be backwards compatible, as it only adds functionality without altering existing behavior.
It would not change the behaviour but it could affect performances. Adding
defaultwould slightly slow downdict.getsince we would need to also parse the keyword. But this must be benchmarked (that's just my gut feeling).The keyword argument should take precedence if both are provided, with a potential deprecation warning for using both simultaneously.
Using both simulteneously should be rejected. There shouldn't be any warning IMO.
Code Style: It adheres to PEP 8 guidelines for function calls, allowing for more readable code when line length is a concern.
This actually increases the line length if you use the keyword argument.
Personally, I'm -1 on this one. While it is great to improve readability, knowing that the second argument of
dict.get()ornext()is for a default value should be something that we do not need to remind directly (IMO, this would not add much value if you're a bit familiar with Python).This is a minor feature, which does not need previous discussion elsewhere
I don't feel it is a minor feature engouh and I feel we should ask a wider community on Discourse: https://discuss.python.org/c/ideas/6. I will leave the issue open for a few days but I think this one should be closed until a consensus has been reached both among core devs and the community (before posting on Discourse, please check if there aren't existing topics on this matter).
Reacted by jibalReacted by RUANG (James Roy)- addedpendingThe issue will be closed if no feedback is providedThe issue will be closed if no feedback is provided
on Sep 27, 2024 I agree with @picnixz viewpoint. Personally, I believe that methods of built-in types should not rely too heavily on keyword arguments; they should be as simple and intuitive as possible, rather than pursuing readability at the expense of practicality (frankly, I don’t want to pass a bunch of parameters when using methods of built-in types, it would make me feel tired).
Moreover, even if keyword arguments are not supported, it shouldn’t affect its usage, right?Reacted by jibalespecially in complex expressions or when the default value is a long expression
Regarding the complex expressions you mentioned, I have written a relatively complex one that uses a lot of f-strings (personally, I think it might not get much more complex than this)
dict.get( f"{ip.a}.{ip.b}.{ip.c}.{ip.d}", f"{ip.a}.{ip.b}.{ip.c}.{ip.d} not found" )
It seems that this doesn’t make the code difficult to read and also keeps it neat.
Reacted by jibalHi @yuriishizawa! Please don't use ChatGPT or other LLMs to generate feature proposals -- they generally form proposals that are hard to follow and make irrelevant points. With that being said, I've needed this exact feature before, but we don't need a new keyword argument;
dict.get("whatever") or default_valueworks just fine.If you really do feel that this is something that's needed, bring it up on DPO. Thanks!
Reacted by jibal- removedpendingThe issue will be closed if no feedback is providedThe issue will be closed if no feedback is provided
on Sep 29, 2024 I'd like to throw in another argument for implementing this feature: The current implementation is contrary to the Python documentation which says:
get(key, default=None)
Return the value for key if key is in the dictionary, else default. If default is not given, it defaults toNone, so that this method never raises a[KeyError](https://docs.python.org/3/library/exceptions.html#KeyError).This syntax and wording implies that both key and default can be passed as keyword arguments.
On the other hand, the CPython built-in help correctly includes a slash at the end, implying that no keyword arguments are accepted:
help(dict.get) Help on method_descriptor: get(self, key, default=None, /) unbound builtins.dict method Return the value for key if key is in the dictionary, else default.It might make sense to update the Python documentation to match the actual behavior, especially if there is consensus among major Python implementations like CPython, PyPy, IronPython, etc. to not allow default as a keyword argument.
Reacted by jibalThis syntax and wording implies that both key and default can be passed as keyword arguments.
I don't think so. There's nothing there that mentions anything about whether it can be passed as a kwarg or not.
Again, there's enough contention here that this won't fly on GitHub--propose it on DPO, and see if it gets any additional community support, then we can reconsider this.
Reacted by jibalI don't think so. There's nothing there that mentions anything about whether it can be passed as a kwarg or not.
The lack of a slash in the function signature implies that all parameters can be passed as arguments or keyword arguments.
Hence, the way the Python language is specified in its documentation,
dict.getaccepts its parameters by name. PyPy, which advertises itself as "a fast, compliant alternative implementation of Python" (emphasis added) implements this feature correctly. Check it out in the online interpreter! CPython on the other hand doesn't fully implement the spec on python.org and incorrectly raises an error when parameters are passed todict.getby name (see online interpreter).propose it on DPO, and see if it gets any additional community support, then we can reconsider this.
What's DPO? This Github repo is the official issue tracker for CPython as per the docs.
Reacted by jibalDPO refers to discuss.python.org. Should have clarified, sorry!
All feature discussion is supposed to happen elsewhere, the issue tracker is used for tracking bugs and features that have already been accepted.
Reacted by jibalAll feature discussion is supposed to happen elsewhere, the issue tracker is used for tracking bugs and features that have already been accepted.
This is basically a matter of fully reflecting PEP 457 and PEP 570 in the documentation. I bet the same issue affects many more functions and methods of the standard library.
dict.getwould only be one example of many. I guess a discussion on DPO on this larger issue would be helpful. In any case, I do not have the time for this discussion.I do think that ambiguities like this one are in fact serious, as they inhibit the portability of Python Code between CPython, PyPy, IronPython and other implementations.
Reacted by jibalIf there's a docs issue, then that's fixable.
If there's a docs issue, then that's fixable.
Even changing the docs requires a discussion for two reasons:
- As far as I can see, for many standard library functions there's ambiguity which parameters can be passed by name. This doesn't only affect
dict.get. This issue is discussed in PEP 457 but no specific plan for addressing the documentation issue is proposed there. Hence any effort to change the docs should encompass most of the standard library, not just this one method. - This ambiguity in the docs on python.org has caused divergence between different implementations of Python as I've outlined above (e.g. PyPy generally allows passing parameters by name). How to deal with that when updating the docs is not trivial.
- The two reasons above are also arguments for changing the CPython implementation instead of just updating the docs.
- As far as I can see, for many standard library functions there's ambiguity which parameters can be passed by name. This doesn't only affect
I have created a PR for the docs difference at #128207.
Mentioned in that PR is the fact that not accepting keyword arguments means that
dictdoes not implementcollections.abc.Mappingwhich does allow keyword arguments:
cpython/Lib/_collections_abc.py
Line 808 in 6f3c2c8
def get(self, key, default=None): As far as I can see, for many standard library functions there's ambiguity which parameters can be passed by name. This doesn't only affect dict.get. This issue is discussed in PEP 457 but no specific plan for addressing the documentation issue is proposed there. Hence any effort to change the docs should encompass most of the standard library, not just this one method.
The documentation is already inconsistent with regards to this - that is, some function definitions have
/and some do not when they could. I think that doing one function at a time is not terrible.This ambiguity in the docs on python.org has caused divergence between different implementation of Python as I've outlined above (e.g. PyPy generally allows passing parameters by name). How to deal with that when updating the docs is not trivial.
Are you suggesting that maybe the docs.python.org documentation should mention the differences between CPython and PyPy here?
The two reasons above are also arguments for changing the CPython implementation instead of just updating the docs.
I think that the documentation should be updated and then if the implementation is changed, the documentation should be updated again to reflect reality.
Reacted by jibalI have since changed my mind, after reading this from the PR (gh-128207):
Relatedly, this means that
dictdoes not implementcollections.abc.Mappingwhich does allow keyword arguments:A dictionary is the de-facto
Mapping, it's probably not great to have inconsistencies like this.I think the issue is more about the fact that
Mappingallows for a keyword argument rather than dict not allowing a keyword argument. In addition, there is still this interrogation:Adding default would slightly slow down dict.get since we would need to also parse the keyword. But this must be benchmarked (that's just my gut feeling).
I don't know whether it will be faster or slower, but I'd advise checking performances first (even if there is a (small but not insurmountable) inconsistency).
- addedinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
on Dec 24, 2024 I'd support allowing
default=as a keyword argument; it seems useful. We should benchmark it to make sure it doesn't slow things down though.Reacted by Peter Bierma, Adam Dangoor, joooeey and Yuri Batista IshizawaAre you suggesting that maybe the docs.python.org documentation should mention the differences between CPython and PyPy here?
Yes. This is either CPython implementation detail or a longstanding bug in CPython, so it should be documented as such. I view docs.python.org as the definition of an abstract language called Python. I don't see a reason why Python (this ideal abstract language) should suddenly stop accepting keyword arguments in
dict.get. But that is exactly what your proposed PR implies.I think that doing one function at a time is not terrible.
Doing one function at a time risks adding even more inconsistencies, as it is not obvious what the proper course of action should be.
I'd support allowing
default=as a keyword argument; it seems useful. We should benchmark it to make sure it doesn't slow things down though.Agree. But what about
key=? That one doesn't seem very useful. PyPy supports passingkey=by keyword too. So does CPython'scollectons.abc.Mapping. So if onlydefault=becomes a positional-and-keyword argument, there would still remain a docs issue to resolve.After a long discussion during the sprint, we (4 core devs at least) decided it was not worth the change. Therefore, unless a real problem arises in the future, I will close this issue (I would prefer that any similar discussion is preceded by a thread on https://discuss.python.org/c/ideas/6 first; builtins deviate a bit from the exact specs because we worry about performance). Thank you for your understanding.
FTR, changing the signature made performance drop by roughly 1 to 3% per
.getnon-keyword call (that is,.get(key, default)) because of how AC parses the arguments.Reacted by Yuri Batista Ishizawa, Adam Turner and Peter Bierma
Feature or enhancement
Proposal:
Background
The
dict.get()method is a commonly used feature in Python for retrieving values from dictionaries with a fallback option. Currently, it accepts positional arguments for the key and default value. However, allowing a keyword argument for the default value could enhance code readability and align with Python's philosophy of explicit naming.Current Behavior
Consider the following code:
This works as expected. However, when attempting to use a keyword argument:
It raises a
TypeError:Proposed Enhancement
Allow the use of the
defaultkeyword argument in thedict.get()method. This would make the code more explicit and easier to read, especially in complex expressions or when the default value is a long expression.Proposed syntax:
Rationale
Readability: This change aligns with PEP 20 (The Zen of Python), specifically the principle "Explicit is better than implicit." Using a keyword argument makes the intention clearer, especially when the default value is complex or when the method call is part of a larger expression.
Consistency: Many Python built-in functions and methods allow both positional and keyword arguments for optional parameters (e.g.,
sorted(iterable, key=None, reverse=False)). This change would bringdict.get()in line with this common pattern.Backwards Compatibility: This change would be backwards compatible, as it only adds functionality without altering existing behavior.
Code Style: It adheres to PEP 8 guidelines for function calls, allowing for more readable code when line length is a concern.
Implementation Considerations
Conclusion
Introducing a
defaultkeyword argument todict.get()would improve code readability and align with Python's design principles. It represents a small but meaningful enhancement to one of Python's most frequently used methods.Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Links to previous discussion of this feature:
No response