Fibo Kowalsky
Fibo Kowalsky

Reputation: 1248

python get key for dict evaluates defulat part even when the key exists

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()?

Upvotes: 0

Views: 106

Answers (3)

vaizki
vaizki

Reputation: 1932

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.

Upvotes: 1

Piotr Grzybowski
Piotr Grzybowski

Reputation: 594

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.

Upvotes: 1

nonDucor
nonDucor

Reputation: 2093

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.

Upvotes: 1

Related Questions