-2

The following code is available (demo)

f=lambda m, x:m and(x&1 and m.pop(0)or m.pop(0)[::-1])+f(m, x+1)
print(f([[4, 3, 2, 1], [5, 6, 7, 8], [12, 11, 10, 9], [13, 14, 15, 16]],0))

# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

Here there is logic:

m.pop(0) if x&1 else m.pop(0)[::-1]

Please explain why when folding to the following view, is the code not executing correctly?

[m.pop(0)[::-1],m.pop(0)][x&1]

I don't know much about Python, will be grateful for any help, thank you.

UPD: If I change the logic, I get this result:

f=lambda m,x:m and([m.pop(0)[::-1],m.pop(0)][x&1])+f(m,x+1)
print(f([[4, 3, 2, 1], [5, 6, 7, 8], [12, 11, 10, 9], [13, 14, 15, 16]],0))

# [1, 2, 3, 4, 13, 14, 15, 16]

PS. Code-golf (If this is important, the essence of the code is that it bypasses the two-dimensional array in the form of a snake)

Solution:

[m.pop(0)[::-1],m.pop(0)][x&1] => (lambda: m.pop(0)[::-1], lambda: m.pop(0))[x&1]().

https://ideone.com/u6Qp4O

wnull
  • 217
  • 6
  • 21

2 Answers2

3

The issue is that the trinary if only evaluates one of its branch so only one pop call occurs. In your code there are two pop calls that both are evaluated.

[m.pop(0)[::-1], m.pop(0)][x&1]

To avoid that, if one must write it this way, and not using an a trinary A if C else B, one has to thunk, lambda:, each case and then after indexing the list of cases, call the case that was selected:

[lambda: m.pop(0)[::-1], lambda: m.pop(0)][x&1]()

One then could remove the common expression:

item = m.pop(0)
[lambda: item[::-1], lambda: item][x&1]()

Doing this before thunking, would result in:

item = m.pop(0)
[item[::-1], item][x&1]

This would not produce an error if item was slice-able. But it would uselessly produce and discard a reversed copy of item. But if the item is say an int when x is odd and a list when even this would result in an error:

>>> 3[::-1]
TypeError: 'int' object has no attribute '__getitem__'

Because all sub expressions in an expression are evaluated unless they have been delayed by a lambda.

A thunk is a term for a function that takes no arguments.

Dan D.
  • 73,243
  • 15
  • 104
  • 123
2

The short-circuiting behavior is different between all three versions of the expression given (if certain elements of m are false). The a and b or c idiom was commonly used before Python had a conditional operator, but is inequivalent if b is false.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76