Your example demonstrates dynamic typing, not weak typing. Dynamic typing generally means that the type of data an object can store is mutable; any target may hold a binding to any kind of object. Contrast that with, say, C#, which is statically typed [*].
int i = 5; // Okay.
i = "5"; // Illegal! i can only hold integers.
Strong typing means that once assigned a value of a particular kind, objects obey strict rules about how they can interact with other objects of various types. Weak typing means that such rules are more relaxed. This doesn't mean that strongly typed languages are necessarily superior in any way; it's just a language design choice.
Python is considered strongly typed because objects have a distinct notion of what they type they are. Incompatible operations between objects cause errors:
>>> 1 + 1 # Add two integers.
2
>>> "1" + "1" # Concatenate two strings.
'11'
>>> 1 + int("1") # Add two integers.
2
>>> "1" + str(1) # Concatenate two strings.
'11'
>>> 1 + "1" # Undefined! Adding integers and strings is meaningless.
Traceback (most recent call last):
File "", line 5, in ?
TypeError: unsupported operand type(s) for +: 'int' and 'str'
But in PHP, the rules are much more relaxed about what is acceptable. Thus it is considered more weakly typed than some other languages.
$x = 1 + "1"; // x is 2
[*] Technically, as of C# 4, C# is statically typed but with opt-in dynamic typing on a per-binding basis, thanks to the dynamic
keyword. A lot of languages these days are adding dynamic capabilities and blurring the lines, so it's becoming increasingly harder to say that "language X is dynamic" and "language Y is static". It's much more of a sliding scale or a spectrum than it is a binary property.