【问题标题】:Comparison Operators for Class Objects (not instances)类对象的比较运算符(不是实例)
【发布时间】:2020-11-08 16:08:32
【问题描述】:

在我当前的项目中,我发现声明子类(类似于 Django 的 Model 语法)比创建基础对象的实例更清晰、更合乎逻辑。在保持简单易读的前提下,我还想在父类中添加比较器。下面是一个简单的例子来说明情况:

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

然而,这会抛出 TypeError: '&gt;' not supported between instances of 'type' and 'type'

我尝试过的事情

经过反思,我理解这意味着丰富的比较方法是从typeobject/class 是一个实例)调用的,所以一个简单的修复,比如将classmethod 装饰器添加到比较方法中不做任何事情。制作Orderable 超类显然也不行,因为这只是type 的另一个实例,因此type 的比较器仍会被调用。我不认为这是可以用metaclass 来实现的,但我对它们的流利程度不足以肯定地说出来。

我的搜索通常返回不相关的主题:

  • “TypeError [etc]”返回所有通用的“'
  • 各种形式的“比较类对象”返回关于比较实例而不是类对象本身的问题
  • 我尝试了类似“比较/排序/排序类型”的方法,但仍然没有相关信息
  • 我在 django.db.models 内浏览了 Django 的 github,但没有注意到我检查的文件中有任何实现(我承认我可能错过了它,因为 django 是一个大包)
  • 检查了types 模块,但它似乎不能满足我的需要(除非我看错了)

目前我可以通过编写Version2.VERSIONNUMBER &gt; Version1.VERSIONNUMBER 在代码中解决它,但我真的很好奇它是如何实现的(因为根据我的经验,您几乎可以在 Python 中做任何事情)。我的假设是这个类必须使用object 子类型来构建,我只是不确定从哪里开始。

【问题讨论】:

  • class Version1(Version): VERSIONUMBER = 1.0Version1 = Version(1.0) 更容易阅读吗?只需使用实例而不是子类。

标签: python python-3.x


【解决方案1】:

警告:在我的脑海中,我不确定你是否能让total_ordering 在这里玩得很好。

但是让比较方法对类起作用的一种方法是使用元类,而不是从父类继承它们。例如:

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

【讨论】:

  • 非常感谢! total_ordering 在进行比较时会抛出一个错误,指出它缺少一个参数 (V1&lt;V2),但无论如何添加其他比较器是微不足道的,所以在我的情况下这不是问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-12
  • 1970-01-01
  • 2021-11-07
  • 1970-01-01
相关资源
最近更新 更多