Aggressively shared-xor-mutable. If an object A has a reference to some other object B, either B is (deeply) immutable or A has the only reference to B. This means that in general, data is only held by some code as long as is needed to operate on it, at which point the data is relinquished.
Personally, I find OO designs to be enhanced by this principle, so I don't think it's only something one does in Rust. I certainly learned it from Rust though.
For what it's worth, following this pattern informally is usually a good idea anyway in Python (and Lua and Ruby and Javascript etc).
Even if B is technically mutable (which 99% of the time it is because almost everything in Python is mutable), just don't mutate it and pretend like you're not allowed to do so.
> Even if B is technically mutable (which 99% of the time it is because almost everything in Python is mutable), just don't mutate it and pretend like you're not allowed to do so.
This gets you pretty far, but it's hard to ensure that nobody else ever mutates B. If B is technically mutable, and there are multiple mutable references to B, then when you invoke some other object in the course of your work, control might come back to you with B mutated without you realizing it. This is why the XOR is so important: if B is shared (with you) and mutable (not by you), B could change under you while you've passed control temporarily to someone else.
This is certainly less problematic than having multiple mutable references, but it's still a source of complexity. As a very small toy example, consider iterating forward over an array while deleting elements.
One of my frustrations when working with Python is that it has been adding very useful FP-inspired tools, but any random library I invoke can pull the rug out from underneath me.
I have long felt that retrofitting a language to add support for immutability/FP constructs is better than nothing but significantly worse than starting with immutability as a core principle.
Lua makes it relatively easy to do this to a table, by assigning a __newindex metamethod which throws an error any time code attempts to assign to a field of a given table.
Which you can get around with rawset, that's what it's there for, but it will catch any idiomatic attempt to mutate the data.
Personally, I find OO designs to be enhanced by this principle, so I don't think it's only something one does in Rust. I certainly learned it from Rust though.