Skip to content

Should the dict.get overload with default value not be generic? #9155

Description

@Avasam

When using dict.get with a default value, it is expected that the key may not be found. Most of the time it's because we're not dealing with literal types, so we can't ensure that a key is part of the dict. But other times, it's we explicitely use a value that has a type we know won't be in range (often None).

See the example below (it is of course minimal and abstracted from a real-world example, but should still show the use):

code_events= {
0: "ZERO_EVENT",
1: "ONE_EVENT",
# ...127: "LAST_EVENT",
}
defparse_foo_code(self, code: int|None):
code=codeand (code&0x7f) # Some bitwise operation to skip bit 8, this just shows we can't use -1 as default. And who knows what other keys could be used in the dictevent=code_events.get(code, "SPECIAL_DEFAULT_FOO_EVENT")
# ... do more with the eventdefparse_bar_code(self, code: int|None):
code=codeand (code&0x7f) # Some bitwise operation to skip bit 8event=code_events.get(code, "SPECIAL_DEFAULT_BAR_EVENT")
# ... do more with the event

Currently it has to be written as such (without a cast). Which adds redundancy checks and no type-safety:

defparse_foo_code(self, code: int|None):
code=codeand (code&0x7f) # Some bitwise operation to skip bit 8ifisinstance(code, int): # You could imagine this could be more complex than just int. Maybe it can't even be easily expressedevent=code_events.get(code, "SPECIAL_DEFAULT_FOO_EVENT")
else:
event="SPECIAL_DEFAULT_FOO_EVENT"# ... do more with the event

What if this definition in dict:

@overloaddefget(self, __key: _KT) ->_VT|None: ...
@overloaddefget(self, __key: _KT, __default: _VT|_T) ->_VT|_T: ...

was changed to:

@overloaddefget(self, __key: _KT) ->_VT|None: ...
@overloaddefget(self, __key: object, __default: _VT|_T) ->_VT|_T: ... # Either object, or Any if it causes variance issue.

What are your thoughts? Any reason this would be a bad idea? From what I can see there are legit sensible use-cases, it stays type-safe, and allows for more concise code. Or just use a cast and call it a day?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions