A “data race” is simultaneous access of memory from multiple threads, where at least one access is a write. It’s undefined behaviour in modern compilers (including LLVM therefore Rust).
Rust prevents that (except unsafe), as does Python.
All “semantic” concurrency bugs that can be written in Python can also be written in Rust.
another definition of a data race condition is that it's a case where different interleavings of thread accesses to shared data produce different results. see https://en.m.wikipedia.org/wiki/Race_condition for more details and background on the concept
such bugs can be written in rust with unsafe, but not without it
hmm, thinking about it more, i wonder if what i'm saying makes sense
Not to mention, Rust chose not to do anything about the memory fence problem. You're probably mostly fine on x86, but acquire/release semantics and all that nonsense still apply when writing concurrent algorithms in Rust (you'll often get lucky if you have something like a queue/channel and use message passing, since implementations of those often have a few fences internally, probably the fences you need for semantic correctness in your own algorithms). You're a lot more likely to see that sort of problem crop up in embedded work.
[0] That's obviously a bad idea, but more intricate concurrent algorithms are tricky to write in Rust for the same reason they're tricky to write in other languages. You get a bit of help from the compiler which you wouldn't really in Python if you design things to leverage the type system and prove the invariants you need to uphold, but the compiler doesn't know about any of those invariants aside from data races.
Every bytecode instruction is implicitly wrapped in a lock.
Of course, you could still get semantic errors by locking the wrong things at the wrong time; but you can do that in Rust as well.