This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Dictionary get(key, default-expression) not short circuit behavior
Type: behavior Stage: resolved
Components: Versions: Python 3.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: eric.smith, martinmeo
Priority: normal Keywords:

Created on 2019-12-18 01:15 by martinmeo, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (2)
msg358602 - (view) Author: Martin Meo (martinmeo) Date: 2019-12-18 01:15
"""
Unexpected behavior report

Dictionary get(key, default-expression) not short circuit behavior

MacOS 10.14.6
sys.version_info(major=3, minor=6, micro=5, releaselevel='final', serial=0)

BACKGROUND
A python dictionary is a data structure that associates a set of keys with a set of values.
Accessing a non-existent key produces a KeyError.
Dictionaries have a get() method.
get(key[, default-expression])
Return the value for key if key is in the dictionary, else default-expression.
If default-expression is not given, it defaults to None, so that this method never raises a KeyError.

EXPECTED BEHAVIOR
get() would only evaluate default-expression if it has to, when key is not found.  It would have short-circuit behavior like boolean operators.

ACTUAL BEHAVIOR
The default-expression DOES get evaluated even when the key IS found in the dictionary. And if default-expression is a function call, the function DOES get called.

"""

denominations = {0:'zero', 1:'one', 2:'two', 3:'three', 4:'four'}
        
def foo(n):
    print('FOO CALLED. n =', n)
    return str(n*10)

words = []
words.append(denominations[1])
words.append(denominations[4])
words.append(denominations.get(1))
words.append(denominations.get(4))
words.append(denominations.get(1, 'ERROR-A'))
words.append(denominations.get(4, 'ERROR-B'))

words.append(denominations.get(22, 'ERROR-1'))
words.append(denominations.get(88, 'ERROR-2'))

words.append(denominations.get(1, foo(1)))
words.append(denominations.get(4, foo(4)))

print(words)



def isItZero(n):
    print('ISITZERO CALLED.  n=', n)
    return False

a = (True or isItZero(9))   # (True or x) is always True so x is not evaluated
msg358605 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-12-18 01:58
.get() is just a regular function call. And like all python functions, all of the arguments are evaluated before the function is called. There is no mechanism in python to delay the evaluation of a arguments.

You might want to look at collections.defaultdict. You can supply a factory function, so that the call is delayed until a missing key is found.
History
Date User Action Args
2022-04-11 14:59:24adminsetgithub: 83264
2019-12-18 01:58:56eric.smithsetstatus: open -> closed

nosy: + eric.smith
messages: + msg358605

resolution: not a bug
stage: resolved
2019-12-18 01:15:17martinmeocreate