> I can't tell what the underlying implementation is, but either way you can't modify them without creating a new tuple so they behave as if they use value-semantics not reference-semantics. (this is what makes tuples safe as defaults in a method, and lists not)
Ahh, you were talking about the semantics, not the implementation. Understood.
Another way to think of this might be in terms of mutability, i.e. tuples are immutable. Pass-by-value versus pass-by-reference for immutable objects doesn't make much difference in the behavior of objects in a language like Python which doesn't have explicit pointers, but it's a big difference for performance.
> If you compare their ids it does look like python makes multiple instances and passes them around by reference
I didn't think of answering my own question this way. Nice!
> but the results might be implementation dependent.
It's possible since Python isn't standardized, but I strongly doubt you'll find a mature implementation that passes potentially-large, variable-sized objects like tuples around by value, for two reasons:
1. Once you get above the size operated on by processor instructions (64 bits on most modern desktop/laptop processors) pass by value requires a memcopy, which is orders of magnitude slower. Tuples can grow past the L1 or L2 cache size, which corresponds to another two orders of magnitude in performnance loss. Comparing this to passing around a 64-bit pointer which is about as fast as passing around any other value.
2. Virtual machines usually implement their own stack. This is easiest to do as an array of same-sized values. Implementing a performant stack with variable-sized elements is a nightmare I wouldn't wish on my worst enemy.