Koan 9: The Unfired Pot

The Hidden Teaching: The Flow of Assignment
Just as a master potter knows that some steps must precede others regardless of the order they’re written, a seasoned Python developer understands that a seemingly simple assignment is not a singular event. It’s a flow. The value does not “flow” from left to right. Python evaluates the right-hand side first and binds that result to each target from left to right.
Part 1: Assignment Chains
Consider a chain of assignments:

This may appear to assign x + 2 to x, y, and z simultaneously. But Python does not work that way. The expression x + 2 is evaluated once, producing the value 12, which is then sequentially bound to z, y, and x. Assignment in Python is a statement, not an expression, so it does not return a value during this process.
Part 2: Identity and Comparisons
Consider the following assignment chain:
list2 = list3 = list1 = [1,2,3]
On the surface, this appears simple. It creates a single list object [1, 2, 3] and binds list1, list3, and list2 to that same object.
This is a shared reference, not a copy.
Modifying one of these variables will affect all others. We can confirm this by checking the identity of the objects using the id() function.
If you're enjoying this post, consider subscribing for more posts like this:

Part 3: Comparison Chains
The same principle of sharing values does not apply to chained comparison operators such as <, > and ==.
1 < x < 10
This expression is not evaluated from right to left. Instead, the interpreter performs a series of distinct comparisons and joins them with an implicit and operator.
The expression 1 < x < 10 is not shorthand for a single operation. It is shorthand for two separate operations:
(1 < x) and (x < 10)
The interpreter is smart enough to perform the minimal number of checks. If 1 < x is False, the expression x < 10 is not evaluated at all because the entire and expression will be False. This is known as short-circuiting and you can use this to your advantage when writing logical expressions:
(high_probability_of_being_false) and (low_probability_of_being_false)
If you write the expression with the higher likelihood of being False first, then you avoid the second expression from being executed. This is something you might have to consider when writing performance sensitive code.
Part 4: Chained Comparisons with Side Effects
What about chained comparisons containing functions with side effects? While Python evaluates a < b < c as (a < b) and (b < c), what happens if b is the result of a function call? Consider the following example:

The output will be Getting B's value... followed by The truth holds. The function get_val_b is called once and its returned value 5 is used for both 1 < 5 and 5 < 10.
The comparison is evaluated as a logical and, but the function call that produces the shared value for both comparisons is only executed once.
Firing the pot
The master potter’s lesson was simple. The order in which instructions are given are not the order in which they must be executed. In Python, chained instructions are executed according to the following rules:
-
Assignment chains evaluate the right-hand side once and bind that result sequentially to each target.
-
Comparison chains are logical combinations of individual comparisons.
When you chain operators you are creating a silent understanding of how values will flow and how logic will be judged.
