Reputation: 1525
In my current project I found it clearer and more logical to declare Subclasses (similar to Django's Model
syntax) rather than creating instances of the base object. On the premise of keeping it simple to read, I also wanted to add comparators to the parent class. Here is a simple example to clarify the situation:
from functools import total_ordering
@total_ordering
class Version():
VERSIONNUMBER = None
def __eq__(self, other):
try: ## catch issubclass(instance, Version)
if issubclass(other, Version): return self.VERSIONNUMBER == other.VERSIONNUMBER
except TypeError: pass
return NotImplemented
def __lt__(self, other):
try:
if issubclass(other, Version): return self.VERSIONNUMBER < other.VERSIONNUMBER
except TypeError: pass
return NotImplemented
class Version1(Version):
VERSIONNUMBER = 1.0
class Version2(Version):
VERSIONNUMBER = 2.0
assert Version2 > Version1
This, however, throws TypeError: '>' not supported between instances of 'type' and 'type'
.
Things I've tried
Upon reflection, I understand this means that the rich comparison methods are being called from type
(which object
/class is an instance of), so a simple fix like adding the classmethod
decorator to the comparison methods doesn't do anything. Making an Orderable
super class is obviously out as well since that would simply be another instance of type
and therefore type
's comparitors would still be called. I don't think this is something that could be implemented with a metaclass
, but I'm not fluent enough in them to say that with absolute certainty.
My searches generally returned irrelevant topics:
django.db.models
but didn't notice any implementations in the files I checked (I'll admit I could have missed it, since django is a large package)types
module, but it doesn't seem to do what I need (unless I misread it)For the time being I can work around it in code by writing Version2.VERSIONNUMBER > Version1.VERSIONNUMBER
, but I'm really curious how it could be implemented (since it has been my experience that you can do just about anything in Python). My assumption is that the class would have to be constructed using an object
subtype, I'm just not sure where to begin with that.
Upvotes: 1
Views: 313
Reputation: 92440
Caveat: Off the top of my head, I'm not sure if you will be able to get total_ordering
to play well here.
But one method to get the comparison methods to work on a class is to use a meta class rather inheriting them from a parent. For example:
class Version_Meta(type):
def __eq__(self, other):
try:
return self.VERSIONNUMBER == other.VERSIONNUMBER
except TypeError: pass
return NotImplemented
def __lt__(self,other):
try:
return self.VERSIONNUMBER < other.VERSIONNUMBER
except TypeError: pass
return NotImplemented
class Version(metaclass=Version_Meta):
VERSIONNUMBER = None
class Version1(Version):
VERSIONNUMBER = 1.0
class Version2(Version):
VERSIONNUMBER = 2.0
Version1 < Version2
# True
Version2 < Version1
# False
Upvotes: 1