Python is strongly typed, although possibly not as much as we might hope. This fails:
"cat" + 1
with a type error, but it happens at runtime. (Oddly enough, Scala permits it.) Python's type system isn't very expressive-- for example, you have "list" and "dict" types but not "list of int"-- and since you can branch without type congruence (because Python's "if" is a statement, not an expression) you can lose static knowledge pretty quickly, but Python does block type errors. It just does so at runtime, which means that the problem may be hard to reproduce and the error/failure distance can be high.I agree with most of what's said in the OP. I just want to push back against the use of "strong" and "static" typing as if they were interchangeable. I'm in the same boat-- generally an advocate for compile-time static typing-- but to conflate static/dynamic with strong/weak is to misrepresent the issue, and unfair to the dynamically-typed languages. All of the modern dynlangs (e.g. Python, Ruby, Clojure) enforce type safety. They just do it at runtime, whereas Haskell, Scala and Ocaml do it at compile time.