Seeking deeper understanding of python equality (==)

Jonathan Kaczynski jonathan.kaczynski at guildeducation.com
Tue May 17 07:15:24 EDT 2022


Thank you for your response Eryk.

I did try using gdb in my original post, but using breakpoint() left me in
the python layer (pdb), not the cpython layer (gdb) and I couldn't figure
out how to drop down.

I see you're using the kernel32 library, so I assume you're on windows. I
only have a mac and getting gdb functional on a mac seems to be onerous (
https://gist.github.com/mike-myers-tob/9a6013124bad7ff074d3297db2c98247),
so I'm performing my testing on a linux container running ubuntu.

The closest equivalent to putting kernel32.DebugBreak() in front of the x
== y line in my test script is os.kill(os.getpid(), signal.SIGTRAP).
Though, this drops me into the signal handling code in the cpython layer,
and after several dozen steps I did not reach the richcompare-related
functions. I'll make another attempt later today.

Thanks to everyone's responses, I have a great idea of what's going on,
now. I appreciate you all.

My goal now is to be able to work with the debugger, like Erik is, so that
next time I am able to perform this investigation in-full. Should I create
a new thread for this question?

Thank you,
Jonathan



On Sat, May 14, 2022 at 1:51 PM Eryk Sun <eryksun at gmail.com> wrote:

> On 5/14/22, Jonathan Kaczynski <jonathan.kaczynski at guildeducation.com>
> wrote:
> >
> > So, I'm still wondering how Py_TYPE(v)->tp_richcompare resolves to __eq__
> > on a user-defined class. Conversely, my understanding is, for a type
> > defined in cpython, like str, there is usually an explicitly
> > defined tp_richcompare function.
>
> Sometimes it's simplest to directly examine an object using a native
> debugger (e.g. gdb in Linux; cdb/windbg in Windows).
>
> With a debugger attached to the interpreter, create two classes, one
> that doesn't override __eq__() and one that does:
>
>     >>> class C:
>     ...     pass
>     ...
>     >>> class D:
>     ...     __eq__ = lambda s, o: False
>     ...
>
> In CPython, the id() of an object is its address in memory:
>
>     >>> hex(id(C))
>     '0x2806a705790'
>     >>> hex(id(D))
>     '0x2806a6bbfe0'
>
> Break into the attached debugger to examine the class objects:
>
>     >>> kernel32.DebugBreak()
>
>     (1968.1958): Break instruction exception - code 80000003 (first chance)
>     KERNELBASE!wil::details::DebugBreak+0x2:
>     00007ffd`8818fd12 cc              int     3
>
> Class C uses the default object_richcompare():
>
>     0:000> ?? *((python310!PyTypeObject *)0x2806a705790)->tp_richcompare
>     <function> 0x00007ffd`55cac288
>      _object*  python310!object_richcompare+0(
>             _object*,
>             _object*,
>             int)
>
> Class D uses slot_tp_richcompare():
>
>     0:000> ?? *((python310!PyTypeObject *)0x2806a6bbfe0)->tp_richcompare
>     <function> 0x00007ffd`55cdef1c
>      _object*  python310!slot_tp_richcompare+0(
>             _object*,
>             _object*,
>             int)
>
> Source code of slot_tp_richcompare():
>
>
> https://github.com/python/cpython/blob/v3.10.4/Objects/typeobject.c#L7610-L7626
>


More information about the Python-list mailing list