so pep 3113 , as pointed out by Arthur Gaspard, contains the complete answer. It also lists a whole bunch of reasons why this is probably not a great example. One of them you found in the annoying side effects of debugging. The more I think, is that your code will break by switching to python3, but I'm not sure / still 2.7 personally.
I wanted to play with what is happening. As some disassembled bytecodes, we can see what happens with these three functions (spoiler: foo and bar have the same bytecodes):
from dis import dis
def foo(a, (b, c) ,d):
return a + b + c + d
def bar(a, b_c, d):
b, c = b_c
return a + b + c + d
def baz(a, b, c, d):
return a + b + c + d
print '\nfoo:'
dis(foo)
print '\nbar:'
dis(bar)
print '\nbaz:'
dis(baz)
Productivity:
foo:
3 0 LOAD_FAST 1 (.1)
3 UNPACK_SEQUENCE 2
6 STORE_FAST 3 (b)
9 STORE_FAST 4 (c)
4 12 LOAD_FAST 0 (a)
15 LOAD_FAST 3 (b)
18 BINARY_ADD
19 LOAD_FAST 4 (c)
22 BINARY_ADD
23 LOAD_FAST 2 (d)
26 BINARY_ADD
27 RETURN_VALUE
bar:
7 0 LOAD_FAST 1 (b_c)
3 UNPACK_SEQUENCE 2
6 STORE_FAST 3 (b)
9 STORE_FAST 4 (c)
8 12 LOAD_FAST 0 (a)
15 LOAD_FAST 3 (b)
18 BINARY_ADD
19 LOAD_FAST 4 (c)
22 BINARY_ADD
23 LOAD_FAST 2 (d)
26 BINARY_ADD
27 RETURN_VALUE
baz:
11 0 LOAD_FAST 0 (a)
3 LOAD_FAST 1 (b)
6 BINARY_ADD
7 LOAD_FAST 2 (c)
10 BINARY_ADD
11 LOAD_FAST 3 (d)
14 BINARY_ADD
15 RETURN_VALUE
. foo bar , baz . , , , , , ( P)