Asked By : BlueBomber
Answered By : Gilles
>>> (3).__sub__("a") NotImplemented >>> "a".__sub__(3) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'str' object has no attribute '__sub__'
The type errors are actually coming from verifications performed by the – operator. When you get down to __sub__, what happens is up to the method provided by the object.
- The object constructed by the literal 3 is a built-in integer; its __sub__ method performs case analysis on the type of the argument. The innards of that method do something like this:
if the argument looks like an integer: perform integer subtraction else if the argument looks like a floating-point number: convert the integer to floating point perform float subtraction … else: return NotImplemented
The fallback case is a design choice of the built-in __sub__ method. It doesn’t do a dynamic type check with a boolean result, but a dynamic type analysis.
- The object constructed by the literal “a” is a built-in string; it has no __sub__ method. There is no type check per se here. The runtime engine does check whether there is a __sub__ method, but only as part of locating it: there isn’t a check operation that’s not intrinsically part of locating the method.
Thus “untyped Python” is a difficult concept to define — you can’t take out the types without taking out fundamental parts of the language. You could phrase the question differently: what if, say, the code of the __add__ method of a string (“a”.__add__) was applied to the data of a built-in integer?
>>> int.__add__("a",1) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: descriptor '__add__' requires a 'int' object but received a 'str'
This here is an actual type check. If this type check wasn’t performed, what would happen would depend on the implementation. In a typical implementation, the code of the __add__ method for integers would attempt to access the object “a” as if it was an integer. Depending on the exact layout of objects in memory, it might do things like:
- treat “a” as the integer 97 (because it’s reading the same bytes and interpreting them differently);
- interpret a location in memory as a pointer to an address, and operate on a bunch of bytes that happen to be present at that address, and thus construct a bogus integer as a result;
- interpret a location in memory as a pointer to an address, and trigger a page fault because this address is not mapped in the calling process, resulting in the process dying of a segmentation fault;
In general, what happens on a typical computer when you remove type checks (static or dynamic) is undefined behavior. Eventually a bunch of bytes is interpreted in a way that’s unrelated to the way it was constructed, which can lead to anything: a wrong result (because the bytes happen to mean something), a segmentation fault or other crash (because the bogus data leads to attempting to access a memory address that isn’t mapped, or to execute data as code which may contain an invalid instruction), weird things happening (because the bogus data leads down a code path that has nothing to do with what the program should have been doing), etc. In C (a language which has no strong typing, meaning that the programmer can easily lie to the compiler about the type of objects), undefined behavior is a fact of life, and it famously can do anything including making daemons fly out of your nose (most computers fortunately lack the requisite hardware). ¹ Not “dynamic languages”, which I don’t recommend using as it’s a lot fuzzier.
Best Answer from StackOverflow
Question Source : http://cs.stackexchange.com/questions/17987