What stays the same? What changes?
The patterns are the same. The language techniques change.
Are there guiding principles like SOLID,
Yes. Indeed, they remain the guiding principles. Nothing changes.
or canonical patterns (perhaps entirely new ones) that a dynamic language newbie should know?
Some things are unique. Mostly the impact is that the implementation techniques change.
A pattern is -- well -- a pattern. Not a law. Not a subroutine. Not a macro. It's just a good idea that gets repeated because it's a good idea.
Good ideas don't go out of style or change dramatically.
Other notes. Python is not "weakly typed". It's more strongly-typed than Java or C++ because there's no cast operation. [Yes, there is a way to fudge the class associated with an object, but it's not the kind of thing that's done except to prove a fussy, legalistic point.]
Also. Most design patterns are based on different ways to exploit polymorphism.
Look at State or Command or Memento as examples. They have class hierarchies to create a polymorphic states, commands or mementos of state changes. Nothing changes significantly when you do this in Python. Minor changes include the relaxation of the precise class hierarchy because polymorphism in Python depends on common methods not common ancestors.
Also, some patterns are simply an attempt to achieve late binding. Most Factory-related patterns are an attempt to allow easy change to a class hierarchy without recompiling every C++ module in the application. This isn't as interesting optimization in a dynamic language. However, a Factory as a way to conceal implementation details still has huge value.
Some patterns are an attempt to drive the compiler and linker. Singleton, for example, exists to create confusing globals but at least encapsulate them. Python singleton classes aren't a pleasant prospect. But Python modules already are singletons, so many of us just use a module and avoid trying to mess with a Singleton class.
Yes, definitely.
Dynamic typing has definite advantages in cases where you want to be able to treat everything as one single type. Serialization/deserialization is one of the classic examples. This is why so much Web programming is done in dynamically-typed scripting languages: they're well-suited to a task which involves a whole lot of converting all sorts of data to and from strings.
For application programming, on the other hand, static languages work much better because trying to treat everything as one single type is not frequently a requirement. You often want to have efficient data structures with data represented as itself and not getting converted to other types very frequently. This makes the features of dynamic typing a drawback instead of a benefit, which is why applications are almost exclusively written in statically typed languages.
Best Answer
Let's get a few things straight:
All those surprising similarities aside, there are some practical differences that do influence the development process:
There is also one type of program that could never have been made without static typing: Singularity, an OS without hardware process boundaries. It's written in a small amount of C, some C#, and a dialect of C# called Spec#, which supports code contracts.
Despite being written in a garbage-collected language, multitasking and interprocess communication performance on this OS is in fact better than anything else out there, due to the fact that all the processes run in one memory space, and due to the formal verification optimizations I mentioned above. You couldn't do this without static typing, because in order for programs not to be able to compromise the rest of the system, the communication objects need to be statically verifiable.
Most of the time, though, architectures should look very much the same. Static languages may make programs easier to reason about in many cases because the types are well-defined, but a well-written dynamic language program would also have types that are, at the very least, well-defined in the developers' minds.