It's a myth that dynamic languages can't have strong types. Python aborts almost immediately whenever it can. For instance, adding a number to a string? Exception. Accessing undefined properties?
Furthermore there's a language-standard static type checker, mypy.
> pattern matching
We have that in Python 3.10.
> immutability-by-default for lists and dictionaries
We do have tuples and frozendict.
Arguably its implementations of functional features are much weaker than "truly" functional ones such as Lisp, Haskell, OCaML or F#.