This may apply to built-in types, but for custom objects you can easily add an implementation for using the + operator on a string and non-string, in both directions:
>>> class MyClass:
def __add__(self, other):
return id(self) + id(other)
def __radd__(self, other):
return id(self) + id(other)
>>> test_str = "test"
>>> test_obj = MyClass()
>>> test_str + test_obj
279616730195648
>>> test_obj + test_str
279616730195648
I wouldn’t particularly recommend doing something like this (as the behavior is externally unclear), but there’s nothing we do to explicitly prevent it. Python takes the philosophy of “consenting adults” quite seriously, and avoids limiting functionality as much as possible.
That’s along the same lines of why Python doesn’t have truly private instance attributes or more strictly enforced encapsulation, unlike Java. You can communicate to the users of an API that certain components should be private (through the use of an underscore or exclusion from __all__), but you can’t entirely prevent them from using those components.