Author eryksun
Recipients elliot.gorokhovsky, eryksun, mdk, ppperry, serhiy.storchaka, tim.peters, vstinner
Date 2017-03-12.04:13:25
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1489292007.1.0.754585357181.issue28685@psf.upfronthosting.co.za>
In-reply-to
Content
> assignment of "__lt__" change the value of the tp_richcompare slot? 

Yes. CPython doesn't implement individual dispatching of the rich-comparison functions. There's a single tp_richcompare slot, so overriding one rich comparison forces the use of slot_tp_richcompare. For built-in types this incurs the performance penalty of using a wrapper_descriptor for the other rich comparisons. For example, overriding F.__lt__ forces calling float.__gt__ for the greater-than comparison. 

Before:

    >>> F() > 1

    Breakpoint 0 hit
    python37_d!float_richcompare:
    00000000`6099d930 4489442418      mov     dword ptr [rsp+18h],r8d
                                              ss:00000056`cefef280=a1670058
    0:000> kc 3
    Call Site
    python37_d!float_richcompare
    python37_d!do_richcompare
    python37_d!PyObject_RichCompare
    0:000> g
    False

After:

    >>> F.__lt__ = lambda a, b: 0
    >>> F() > 1

    Breakpoint 0 hit
    python37_d!float_richcompare:
    00000000`6099d930 4489442418      mov     dword ptr [rsp+18h],r8d
                                              ss:00000056`cefef0a0=a39d7c70
    0:000> kc 9
    Call Site
    python37_d!float_richcompare
    python37_d!wrap_richcmpfunc
    python37_d!richcmp_gt
    python37_d!wrapper_call
    python37_d!_PyObject_FastCallDict
    python37_d!call_unbound
    python37_d!slot_tp_richcompare
    python37_d!do_richcompare
    python37_d!PyObject_RichCompare

The __gt__ wrapper_descriptor gets bound as a method-wrapper, and the method-wrapper tp_call is wrapper_call, which calls the wrapper function (e.g. richcmp_gt) with the wrapped function (e.g. float_richcompare). The object ID in CPython is the object address, so we can easily get the address of the __gt__ wrapper_descriptor to confirm how these C function pointers are stored in it:

    >>> id(vars(float)['__gt__'])
    2154486684248

    0:001> ln @@(((PyWrapperDescrObject *)2154486684248)->d_base->wrapper)
    (00000000`60a20580)   python37_d!richcmp_gt   |
    (00000000`60a205c0)   python37_d!slot_tp_finalize
    Exact matches:
        python37_d!richcmp_gt (struct _object *, struct _object *, void *)

    0:001> ln @@(((PyWrapperDescrObject *)2154486684248)->d_wrapped)
    (00000000`6099d930)   python37_d!float_richcompare   |
    (00000000`6099e6f0)   python37_d!float_getzero
    Exact matches:
        python37_d!float_richcompare (struct _object *, struct _object *, int)
History
Date User Action Args
2017-03-12 04:13:27eryksunsetrecipients: + eryksun, tim.peters, vstinner, serhiy.storchaka, ppperry, mdk, elliot.gorokhovsky
2017-03-12 04:13:27eryksunsetmessageid: <1489292007.1.0.754585357181.issue28685@psf.upfronthosting.co.za>
2017-03-12 04:13:27eryksunlinkissue28685 messages
2017-03-12 04:13:25eryksuncreate