Strictly speaking, str not a function. This is a type. When you call str(c) , Python goes through the usual procedure to generate an instance of the type, calling str.__new__(str, c) to create an object (or reuse an existing object) , and then invoke the __init__ method to initialize it .
str.__new__(str, c) calls the C level function PyObject_Str , which calls _PyObject_Str , which calls your __str__ method. The result is an instance of S , so it is considered a string, and _PyObject_Str decides that it is good enough, and not try to force the object with type(obj) is str to the result. So str.__new__(str, c) returns cs .
Now we go to __init__ . Since the str argument was c , it is also passed to __init__ , so Python calls cs__init__(c) . __init__ calls print(c) , which you think will call str(c) and lead to infinite recursion. However, the PRINT_ITEM calls C-level PyFile_WriteObject to write the object and which calls PyObject_Str instead of str , so it skips __init__ and doesnβt solve endlessly. Instead, it calls c.__str__() and prints the resulting instance of S , since the instance of S is a string.
source share