Steve Jorgensen wrote:
Steve Jorgensen wrote:
Steve Jorgensen wrote: <snip> The problem I came up with trying to spike out my proposal last night is that there doesn't seem to be anyway to implement it without creating infinite recursion in the issublcass call. If I make Orderable a real or virtual subclass of ProtoOrderable and Orderable's __subclasshook__ or metaclass __subclasscheck__ (I tried both ways) tries to check whether C is a subclass of ProtoOrderable, then an infinite recursion occurs. It wasn't immediately obvious to me why that is the case, but when I thought about it deeply, I can see why that must happen. An alternative that I thought about previously but seems very smelly to me for several reasons is to have both Orderable and NonOrderable ABCs. In that case, what should be done to prevent a class from being both orderable and non-orderable or figure out which should take precedence in that case? As a meta-solution (wild-assed idea) what if metaclass registration could accept keyword arguments, similar to passing keyword arguments to a class definition? That way, a single ABC (ProtoOrderable or whatever better name) could be a real or virtual subclass that is explicitly orderable or non-orderable depending on orderable=<True/False>. I have been unable to implement the class hierarchy that I proposed, and I think I've determined that it's just not a practical fit with how the virtual bas class mechanism works, so… Maybe just a single TotalOrdered or TotalOrderable ABC with a register_explicit_only method. The __subclasshook__ method would skip the rich comparison methods check and return NotImplemented for any class registered using register_explicit_only (or any of its true subclasses). The only weird edge case in the above is that is someone registers another ABC using TotalOrdered.register_explicit_only and uses that as a virtual base class of something else, the register_explicit_only registration will not apply to the virtual subclass. I'm thinking that's completely acceptable as a known limitation if documented? Code spike of that idea: from abc import ABCMeta from weakref import WeakSet
class TotallyOrderable(metaclass=ABCMeta): _explicit_only_registry = WeakSet()
@classmethod def register_explicit_only(cls, C): if cls is not TotallyOrderable: raise NotImplementedError( f"{cls.__name__} does not implement 'register_explicit_only'")
cls._explicit_only_registry.add(C)
@classmethod def __subclasshook__(cls, C): if cls is not TotallyOrderable: return NotImplemented
for B in C.__mro__: if B in cls._explicit_only_registry: return NotImplemented
return cls._check_overrides_rich_comparison_methods(C)
@classmethod def _check_overrides_rich_comparison_methods(cls, C): mro = C.__mro__ for method in ('__lt__', '__le__', '__gt__', '__ge__'): for B in mro: if B is not object and method in B.__dict__: if B.__dict__[method] is None: return NotImplemented break else: return NotImplemented return True
Naming question: Should an abstract base class for this concept be named `TotalOrderable`, `TotallyOrderable`, `TotalOrdered`, or `TotallyOrdered`?