Home > Software engineering >  python get key for dict evaluates defulat part even when the key exists
python get key for dict evaluates defulat part even when the key exists

Time:12-09

My understanding of dict.get() was that if the key exists, then no evaluation of the default argument is made. And several sources implicitly leave this kind of interpretation. But it turns out that it is not the case.

Let's assume there is a dict that has integer keys either in str or int type. So, one line to retrieve a value module key type would be to use .get with a default value being dependent on the key of an alternative type.

>>> d = {'2':4} 
>>> d.get(2, d['2'])
4
>>> d.get('2', d[2])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 2

What's the point of evaluating the default argument if the key exists? Is it just a bad design of the method or I am overgeneralize the intended functionality of .get()?

CodePudding user response:

The main difference in this case is that the expression d[2] must be evaluated before it is passed as an argument to the get function.

An exception occurs because you are referring in this expression to an integer key 2 that does not exist, before check if d['2'] key exists in that dictionary.

Please find the reference: Expressions 6.3.4. Calls

The primary must evaluate to a callable object (user-defined functions, built-in functions, ... and all objects having a __call__() method are callable). All argument expressions are evaluated before the call is attempted.

CodePudding user response:

Python is not a lazy language, so all the arguments to a function are evaluated before the function is called. That means that, in you second example, d[2] will be evaluated before the call to d.get. There are languages (like Haskell) that would accept this code, since the arguments are only evaluated as needed.

CodePudding user response:

The argument is always evaluated and I'm not aware of any main stream procedural languages that would allow functions to be declared so that evaluation of parameters would be deferred until somehow resolved explicitly.

How to defer evaluation:

d = { '2': 4 }
x = d.get('3', lambda: d[2])
print(x() if callable(x) else x)

.. but this is a pretty silly example.

Edit: Another (dangerous) way to defer evaluation:

x = d.get('2', False) or d[2]

.. assuming no valid results from the dict evaluate to False (like 0 or None). This is a very good way to shoot yourself in the foot.

  • Related