Repository navigation
Allow default keyword argument in dict.get() method #124675
Description
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:
my_dict = {"a": 1, "b": 2, "c": 3}
print(my_dict.get("b", "Not found"))This works as expected. However, when attempting to use a keyword argument:
print(my_dict.get("b", default="Not found"))It raises a TypeError:
Traceback (most recent call last):
File "/path/to/script.py", line 3, in <module>
print(my_dict.get("b", default="Not found"))
TypeError: dict.get() takes no keyword arguments
Proposed Enhancement
Allow the use of the default keyword argument in the dict.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:
my_dict.get("key", default="default_value")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
- The current positional argument for the default value should still be supported for backwards compatibility.
- The keyword argument should take precedence if both are provided, with a potential deprecation warning for using both simultaneously.
Conclusion
Introducing a default keyword argument to dict.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
Activity
picnixz commentedon Sep 27, 2024
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.
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.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).Using both simulteneously should be rejected. There shouldn't be any warning IMO.
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).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).
rruuaanng commentedon Sep 28, 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?
rruuaanng commentedon Sep 28, 2024
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)
It seems that this doesn’t make the code difficult to read and also keeps it neat.
ZeroIntensity commentedon Sep 29, 2024
Hi @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!
joooeey commentedon Oct 24, 2024
I'd like to throw in another argument for implementing this feature: The current implementation is contrary to the Python documentation which says:
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:
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.
ZeroIntensity commentedon Oct 24, 2024
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.
joooeey commentedon Oct 28, 2024
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).What's DPO? This Github repo is the official issue tracker for CPython as per the docs.
ZeroIntensity commentedon Oct 28, 2024
DPO 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.
joooeey commentedon Oct 28, 2024
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.
ZeroIntensity commentedon Oct 29, 2024
If there's a docs issue, then that's fixable.
joooeey commentedon Nov 4, 2024
Even changing the docs requires a discussion for two reasons:
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.adamtheturtle commentedon Dec 24, 2024
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
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.Are you suggesting that maybe the docs.python.org documentation should mention the differences between CPython and PyPy here?
I think that the documentation should be updated and then if the implementation is changed, the documentation should be updated again to reflect reality.
ZeroIntensity commentedon Dec 24, 2024
I have since changed my mind, after reading this from the PR (gh-128207):
A dictionary is the de-facto
Mapping, it's probably not great to have inconsistencies like this.cc @JelleZijlstra
picnixz commentedon Dec 24, 2024
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: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).
JelleZijlstra commentedon 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.joooeey commentedon Jan 7, 2025
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.Doing one function at a time risks adding even more inconsistencies, as it is not obvious what the proper course of action should be.
joooeey commentedon Jan 7, 2025
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.abcwarbot commentedon Sep 16, 2025
picnixz commentedon Sep 16, 2025
abcwarbot commentedon Sep 16, 2025
picnixz commentedon Sep 16, 2025
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.