str(obj) not calling obj.__str__?

Hello, I just noticed that calling `str(x)` is actually doing (in CPython `PyObject_Str`) `type(x).__str__(x)` rather than `x.__str__()`. Context: I wanted to override __str__ for certain objects in order to “see them better”. I'm wondering why not do `x.__str__()` Best regards, -- Jérôme

This is explained in "Special Method Lookup": https://docs.python.org/3/reference/datamodel.html#special-method-lookup Short version: For both correctness and performance, special methods (those that begin and end with double underscores) are typically looked up on the class, not the instance. If you want to override on a per-instance level, have a non-special method that __str__ invokes, that can be overridden on a per-instance basis. On Sun, Feb 23, 2020 at 2:30 AM Jérôme Carretero <cj-python@zougloub.eu> wrote:

Thanks Josh for your prompt reply. All clear. Regards, -- Jérôme PS: Somehow I had never encountered a situation exacerbating the subtleties of implicit invocations of special methods, and hadn't read or integrated that section of the documentation, then when encountering the “problem” I didn't make my way to the docs. And now I also see that right when opening § 3.3. Special method names ¶ 1 it's stated that “`x[i]` is roughly equivalent to `type(x).__getitem__(x, i)`”. I'll be more careful next time! On Sun, 23 Feb 2020 02:35:24 +0000 Josh Rosenberg <shadowranger+pythonideas@gmail.com> wrote:

In unittest.mock.MagicMock I solve this problem by having __new__ create a new subclass for every instantiation. Setting any magic method on the instance is promoted to the type via __setattr__. That way every instance can have unique magic methods without affecting other instances. Michael On Sun, 23 Feb 2020 at 04:21, Jérôme Carretero <cj-python@zougloub.eu> wrote:
-- Michael Foord Python Consultant, Contractor and Trainer https://agileabstractions.com/

On Sun, 23 Feb 2020 at 11:25, Michael Foord <fuzzyman@gmail.com> wrote:
The other little bit of trickery is that MagicMock gets all the magic methods by default and they're all MagicMock objects. To avoid instantiating MagicMock recursively creating MagicMocks forever the magic methods are descriptors that put a new MagicMock instance onto the subclass on first access via an instance. I could probably have saved a lot of effort by overriding __getattribute__ (which can intercept magic method lookups unlike __getatttr__) instead of the descriptor solution. At the time I didn't know that. There's still a bunch of jiggery-pokery to set valid default return values on a bunch of the methods (some are type checked on the return value and some aren't *sigh*), so maybe it's unavoidable. I had fun getting mock to work. Michael
-- Michael Foord Python Consultant, Contractor and Trainer https://agileabstractions.com/

This is explained in "Special Method Lookup": https://docs.python.org/3/reference/datamodel.html#special-method-lookup Short version: For both correctness and performance, special methods (those that begin and end with double underscores) are typically looked up on the class, not the instance. If you want to override on a per-instance level, have a non-special method that __str__ invokes, that can be overridden on a per-instance basis. On Sun, Feb 23, 2020 at 2:30 AM Jérôme Carretero <cj-python@zougloub.eu> wrote:

Thanks Josh for your prompt reply. All clear. Regards, -- Jérôme PS: Somehow I had never encountered a situation exacerbating the subtleties of implicit invocations of special methods, and hadn't read or integrated that section of the documentation, then when encountering the “problem” I didn't make my way to the docs. And now I also see that right when opening § 3.3. Special method names ¶ 1 it's stated that “`x[i]` is roughly equivalent to `type(x).__getitem__(x, i)`”. I'll be more careful next time! On Sun, 23 Feb 2020 02:35:24 +0000 Josh Rosenberg <shadowranger+pythonideas@gmail.com> wrote:

In unittest.mock.MagicMock I solve this problem by having __new__ create a new subclass for every instantiation. Setting any magic method on the instance is promoted to the type via __setattr__. That way every instance can have unique magic methods without affecting other instances. Michael On Sun, 23 Feb 2020 at 04:21, Jérôme Carretero <cj-python@zougloub.eu> wrote:
-- Michael Foord Python Consultant, Contractor and Trainer https://agileabstractions.com/

On Sun, 23 Feb 2020 at 11:25, Michael Foord <fuzzyman@gmail.com> wrote:
The other little bit of trickery is that MagicMock gets all the magic methods by default and they're all MagicMock objects. To avoid instantiating MagicMock recursively creating MagicMocks forever the magic methods are descriptors that put a new MagicMock instance onto the subclass on first access via an instance. I could probably have saved a lot of effort by overriding __getattribute__ (which can intercept magic method lookups unlike __getatttr__) instead of the descriptor solution. At the time I didn't know that. There's still a bunch of jiggery-pokery to set valid default return values on a bunch of the methods (some are type checked on the return value and some aren't *sigh*), so maybe it's unavoidable. I had fun getting mock to work. Michael
-- Michael Foord Python Consultant, Contractor and Trainer https://agileabstractions.com/
participants (3)
-
Josh Rosenberg
-
Jérôme Carretero
-
Michael Foord