Should isinstance call __getattribute__?
I'm looking for some guidance on a bug report involving isinstance and __getattribute__` please. The issue is that if your class overloads `__getattribute__`, calling isinstance on an instance will call the overloaded `__getattribute__` method when looking up `__class__`, potentially causing isinstance to fail, or return the wrong result. See b.p.o. #32683 https://bugs.python.org/issue32683 I see no reason why this isn't working as designed, __getattribute__ is intended to overload attribute access, and that could include the `__class__` attribute. Am I wrong? It has been suggested that isinstance should call `object.__getattribute__` and bypass the class' overloaded method, but I expect that would probably break objects which intentionally lie about their class. (Mocks? Stubs? Proxies?) Thanks, Steve
On 9 Dec 2021, at 16:41, Steven D'Aprano <steve@pearwood.info> wrote:
I'm looking for some guidance on a bug report involving isinstance and __getattribute__` please.
The issue is that if your class overloads `__getattribute__`, calling isinstance on an instance will call the overloaded `__getattribute__` method when looking up `__class__`, potentially causing isinstance to fail, or return the wrong result.
See b.p.o. #32683
https://bugs.python.org/issue32683
I see no reason why this isn't working as designed, __getattribute__ is intended to overload attribute access, and that could include the `__class__` attribute. Am I wrong?
It has been suggested that isinstance should call `object.__getattribute__` and bypass the class' overloaded method, but I expect that would probably break objects which intentionally lie about their class. (Mocks? Stubs? Proxies?)
https://mail.python.org/pipermail/python-dev/2015-October/141953.html <https://mail.python.org/pipermail/python-dev/2015-October/141953.html> is an old thread about the difference between type(x)/Py_TYPE(x) and x.__class__ that contains some insight about this. Proxy types are one use case, although with some sharp edges. Ronald — Twitter / micro.blog: @ronaldoussoren Blog: https://blog.ronaldoussoren.net/
On Thu, Dec 09, 2021 at 05:19:00PM +0100, Ronald Oussoren wrote:
https://mail.python.org/pipermail/python-dev/2015-October/141953.html is an old thread about the difference between type(x)/Py_TYPE(x) and x.__class__ that contains some insight about this.
Thanks for the link Ronald, I remember that thread. It didn't really clarify things to me at the time, and re-reading it, it still doesn't.
Proxy types are one use case, although with some sharp edges.
I'm not looking for use cases. I'm looking for a better understanding of how type() and isinstance() (and presumably issubclass) work. The best I can see is that type() sometimes believes __class__ but not always, that you can sometimes change __class__ but not always, but the rules that control when and why (or why not) are not clear or documented, as far as I can see. Is there a reference for how type(obj) and isinstance(obj, T) are intended to work, or is the implementation the only reference? Thanks in advance, -- Steve
On 10 Dec 2021, at 14:40, Steven D'Aprano <steve@pearwood.info> wrote:
On Thu, Dec 09, 2021 at 05:19:00PM +0100, Ronald Oussoren wrote:
https://mail.python.org/pipermail/python-dev/2015-October/141953.html is an old thread about the difference between type(x)/Py_TYPE(x) and x.__class__ that contains some insight about this.
Thanks for the link Ronald, I remember that thread. It didn't really clarify things to me at the time, and re-reading it, it still doesn't.
That’s because the difference between the two is not clear, and it doesn’t help that C extensions (and CPython itself) use an API that always look at the object’s type slot and not at the ``__class__`` attribute (with APIs such as ``PyObject_TypeCheck`` and ``PyDict_Check``).
Proxy types are one use case, although with some sharp edges.
I'm not looking for use cases. I'm looking for a better understanding of how type() and isinstance() (and presumably issubclass) work. The best I can see is that type() sometimes believes __class__ but not always, that you can sometimes change __class__ but not always, but the rules that control when and why (or why not) are not clear or documented, as far as I can see.
Is there a reference for how type(obj) and isinstance(obj, T) are intended to work, or is the implementation the only reference?
I’m not sure how much of this is documented to be honest. If the documentation is lacking there’s a change for someone to dig deep and help writing the documentation ;-) Changing the type of an instance by assigning to ``__class__`` is basically allowed when the C layout for instances of the two classes are compatible, the implementation contains the details about this. IIRC this requires that both classes inherit from a shared base class and none of the intermediate classes introduce new slots (or the C equivalent of this). Ronald
Thanks in advance,
-- Steve _______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-leave@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/GB2S2SMN... Code of Conduct: http://python.org/psf/codeofconduct/
— Twitter / micro.blog: @ronaldoussoren Blog: https://blog.ronaldoussoren.net/
participants (2)
-
Ronald Oussoren
-
Steven D'Aprano