0

Is there a way to avoid such a "less expected" behavior? So if the same key is used more than once something will fire up?

In [3]: a = {"a": 2, "a": 3, "a": 5}

In [4]: a
Out[4]: {'a': 5}

In [5]: type(a)==dict
Out[5]: True

but thankfully this is invalid:

In [6]: dict(a=2,a=4)
  File "<ipython-input-5-733265236ee3>", line 1
    dict(a=2,a=4)
            ^
SyntaxError: keyword argument repeated
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
0x90
  • 39,472
  • 36
  • 165
  • 245
  • 4
    The second form isn't specifically a limitation of the `dict` constructor, it's that the language doesn't allow two keyword arguments with the same name. That would apply to any function call. – sj95126 Aug 04 '22 at 13:06
  • 1
    This is [the documented behavior](https://docs.python.org/3/library/stdtypes.html#mapping-types-dict): "If a key occurs more than once, the last value for that key becomes the corresponding value in the new dictionary." – Thierry Lathuille Aug 04 '22 at 13:07
  • See also https://stackoverflow.com/questions/4999233/how-to-raise-error-if-duplicates-keys-in-dictionary – mkrieger1 Aug 04 '22 at 13:13
  • Some linters will warn you about this. E.g. PyCharms built-in Linter and flake8 say something like "dictionary contains duplicate keys" – Wombatz Aug 04 '22 at 13:20

1 Answers1

3

How about turning the question around: why shouldn't it be valid? You're in charge of the code, it's not like users can make this mistake for you, or provide input you have no control over that would cause it.

And it allows for things like this to work:

{c: n for n, c in enumerate(['a', 'a', 'b'])}

Result:

{'a': 1, 'b': 2}

The example by itself is hardly useful, but you can imagine situations where the simple list is a generator and you may not have control over there being any duplicates. The dict keeping track of the last key generated could be useful.

Also, it's the same for the constructor function:

dict([('a', 0), ('a', 1), ('b', 2)])

As pointed out in the comments by user @sj95126, the reason it doesn't work for the example you gave, is because that's a way of calling a function with duplicate keyword arguments, and that's not allowed - it's not to do with the actual dictionary definition.

User @chepner makes a point in the comments worth repeating as well: an expression like {"a": 2, "a": 3, "a": 5} is a syntactically correct dictionary definition: hashable type keys with values of any type. Disallowing repetition of keys would mean checking the actual values of the keys, not just their types. The keys of a dictionary are data, not identifiers in the language (like function argument names), you check key values at runtime, and you're allowed to add more at runtime (unlike object attributes, for example).

Since {"a": 2, "a": 3, "a": 5} is syntactically correct, having a robust way of interpreting it is vastly preferable to it causing runtime errors - and Python's interpretation is a good example.

Grismar
  • 27,561
  • 4
  • 31
  • 54
  • Makes sense. It similar to the behavior of updating the dict with new values. Good point. – 0x90 Aug 04 '22 at 13:07
  • 1
    Another point: in a function call, the keyword argument *must* use a hard-coded identifier, meaning the parser can catch this as a syntax error. In a `dict` display, a key can be any expression; not until runtime will you know what hashable value that expression will evaluate to. It's probably too much work for too little benefit to catch the special case of duplicated constants in the key datum list. – chepner Aug 04 '22 at 13:12
  • 1
    Catch errors as early as possible, but not all errors can be turned into syntax errors. – chepner Aug 04 '22 at 13:13