Earlier quoted context omitted.
> In the mutation example you suggest, if a reference to x isn't being passed into foo, how could foo modify x The important point is that it's not "a reference to x" that gets passed, it's a copy of x's value. x's value, like the value of all Python variables, is a reference to some object. The same thing applies to setting variables in Python in general: x = {1:2} # x is a new variable that references some dict y =…
This is what confuses me; it sounds like what you're saying is Python isn't pass-by-reference, it's pass-by-value, and that value is sometimes a reference? Honestly, "x's value, like the value of all Python variables, is a reference to some object" makes me think it's more accurate to call Python pass-by-reference only.
What those values represent and how they can be used is a completely different topic. Take the following code:
x = "/dirs/sub/file.txt"
with open(x, "w") as file:
file.write("abc")
foo(x)
with open(x, "r") as file:
print(file.read_all()) #prints "def"
def foo(z):
with open(z, "w") as file:
file.write("def")
Here x is in essence a "reference to a file". When you pass x to foo, it gets a copy of that reference in z. But both x and z refer to the same file, so when you modify the file, both see the changes. The calling convention is passing a copy of the value to the function. It doesn't care what that value represents.