[Python] can a class detect that it's being subclassed?

62 views
Skip to first unread message

Jeroen Demeyer

unread,
Mar 3, 2015, 11:38:35 AM3/3/15
to sage-devel
This is more a Python question, but maybe somebody knows a solution.

I want to define some kind of hook on a class E which is called whenever
another class inherits from E.

So the moment somebody does

class SomeOtherClass(E):
...

I want a hook function to be called with SomeOtherClass as argument, in
order to monkey-patch SomeOtherClass. Is this possible?


Note: what I *really* want to do is to fix __cmp__() vs. _cmp_(). Sage
has the very annoying convention that Python classes should use __cmp__
but Cython classes should use _cmp_. This means that __richcmp__ needs
to pull some crazy hacks to determine whether the class is a Python or
Cython class.

The obvious solution is to change __cmp__ to _cmp_ for every Python
class inheriting from Element (a lot of effort). The non-efficient
solution is to check for __cmp__ every time _cmp_ needs to be called.
The optimal solution would be to somehow automatically monkey-patch
those classes to define _cmp_ as alias for __cmp__.

Simon King

unread,
Mar 3, 2015, 12:08:27 PM3/3/15
to sage-...@googlegroups.com
Hi Jeroen,

On 2015-03-03, Jeroen Demeyer <jdem...@cage.ugent.be> wrote:
> I want to define some kind of hook on a class E which is called whenever
> another class inherits from E.
>
> So the moment somebody does
>
> class SomeOtherClass(E):
> ...
>
> I want a hook function to be called with SomeOtherClass as argument, in
> order to monkey-patch SomeOtherClass. Is this possible?

Perhaps a metaclass can do it? If E has a metaclass M, then SomeOtherClass
has metaclass M as well.
But M's job is to create E and SomeOtherClass out of the given data.
Hence, it can do whatever you want with SomeOtherClass.

> Note: what I *really* want to do is to fix __cmp__() vs. _cmp_(). Sage
> has the very annoying convention that Python classes should use __cmp__
> but Cython classes should use _cmp_.

Then a metaclass will not help you, as it is not supported by Cython
extension classes.

Best regards,
Simon

Volker Braun

unread,
Mar 3, 2015, 12:12:34 PM3/3/15
to sage-...@googlegroups.com
Yes, metaclass does exactly that. E.g. add

class SageObject(object):
    __metaclass__ = SageClass

Possible issues are that there are already some metaclasses used in Sage, e.g. some of the category stuff relies on it but doesn't convey the metaclass systematically.

Also, there are various Cython limitations (since you can't monkey-patch cdef stuff)

Volker Braun

unread,
Mar 3, 2015, 12:14:36 PM3/3/15
to sage-...@googlegroups.com
Also, Python 3 will one way or the other fix your problem: the cmp() function and the __cmp__() magic methods are no more.


On Tuesday, March 3, 2015 at 5:38:35 PM UTC+1, Jeroen Demeyer wrote:

Jeroen Demeyer

unread,
Mar 3, 2015, 5:20:38 PM3/3/15
to sage-...@googlegroups.com
On 2015-03-03 18:07, Simon King wrote:
> Then a metaclass will not help you, as it is not supported by Cython
> extension classes.

Yes indeed, __metaclass__ doesn't do anything in Cython.

The problem I am facing in #17890 is that currently, when a Python(!)
class defines __cmp__ and _cmp_, then __cmp__ takes priority. That's the
way how things are in done in Sage currently. The problem is that the
check for __cmp__ is a lot slower than the check for _cmp_ (the latter
is a Cython call). There are some very ugly hacks to speed this up
anyway and I would like to get rid of these hacks.

Ideally, _cmp_ should have priority over __cmp__. This will break
inheritance chains like

Element > A > B

where A is a Cython class with _cmp_ and B is a Python class with
__cmp__. In these cases, one would need to define _cmp_ also for B.
Reply all
Reply to author
Forward
0 new messages