The value of bob is 1 as of the first line of code which assigns 1 to a variable named bob. Then the string "bob" is assigned to the variable bob, replacing the value of 1. It's the same variable, just with different values. This is dynamic typing since the program will be type checked when these lines of code are executed.
"Strong" and "Weak" typing are imprecise terms but Python fits within the "Strong" group. For example:
test1 = 1
test2 = "this is a string"
test3 = test1 + test2 #This will fail at runtime.
Specifically the error will be this:
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
test3 = test1 + test2
TypeError: unsupported operand type(s) for +: 'int' and 'str'
If Python were weakly typed, this would have worked, probably as string concatenation. Explicit casting of test1 via the str() function would be required to do the same in Python proper.
The differing addresses for 1 and "bob" in the initial example have to do with 1 and "bob" both being alias for objects. Since they are not the same object, they have different addresses. bob the variable name is just a label for one of those two object references. Specifically, whichever was last assigned to it.