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: dict.setdefault: Bug: default argument is ALWAYS evaluated, i.e. no short-circuit eval
Type: behavior Stage:
Components: Versions: Python 2.6
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: albert.neu, amaury.forgeotdarc, eric.smith
Priority: normal Keywords:

Created on 2011-01-18 10:54 by albert.neu, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (3)
msg126456 - (view) Author: Albert (albert.neu) Date: 2011-01-18 10:54
Hello!

Is it intentional, that the default argument is ALWAYS evaluated, even if it is not needed???

Is it not a bug, that this method has no short-circuit eval (http://en.wikipedia.org/wiki/Short-circuit_evaluation)
??

Example1:
=========
infinite = 1e100

one_div_by = {0.0 : infinite}

def func(n):
    return one_div_by.setdefault(float(n), 1/float(n))

for i in [1, 2, 3, 4]:
    print i, func(i)
print one_div_by
# works!!

for i in [0, 1, 2, 3, 4]:     # added 0 -> FAIL!
    print i, func(i)
print one_div_by
# fail!!



Example2:
=========
fib_d = {0 : 0, 1 : 1}

def fibonacci(n):
    return fib_d.setdefault(n, fibonacci(n-1) + fibonacci(n-2))

for i in range(10):
    print i, fibonacci(i)
print fib_d
msg126458 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2011-01-18 12:14
setdefault() is a method, its arguments are evaluated then the function is called. This is not a bug, and this behavior cannot change.

If you are trying to "cache" the computation of a function, you should try "memoizing" techniques, like the one mentioned here: http://code.activestate.com/recipes/52201-memoizing-cacheing-function-return-values/
Then you can write::

    @Memoize
    def fib(n):
        return fib(n-1) + fib(n-2)
    fib.memo = {(0,): 1, (1,): 1}

    @Memoize
    def func(n):
        return 1/float(n)
    func.memo = {(0.0,): infinite}
msg126467 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2011-01-18 15:28
Or use a collections.defaultdict, which has a factory function as a constructor argument. It sort of depends on what you're trying to do.
History
Date User Action Args
2022-04-11 14:57:11adminsetgithub: 55139
2011-01-18 15:28:04eric.smithsetnosy: + eric.smith
messages: + msg126467
2011-01-18 12:14:12amaury.forgeotdarcsetstatus: open -> closed

nosy: + amaury.forgeotdarc
messages: + msg126458

resolution: not a bug
2011-01-18 10:54:36albert.neucreate