如何在python中实现可以比较,排序等的类

时间:2018-09-05 20:08:50

标签: python

我正在尝试编写Card类,并希望确保可以在其上使用比较运算符,以及使用Card对象列表的max,min和sort。

我读到要实现这一点,我只需要实现__cmp__,但是当我这样做时,我的单元测试将无法通过,因此我最终实现了所有比较魔术方法__gt__,{{ 1}},__lt__

我想摆脱代码中的膨胀,并尽可能删除__eq__的所有比较方法。

我正在使用Python 3.5 Anaconda发行版。

这是我当前的实现方式:

__cmp__

最初不是我现在拥有的所有魔术方法,__ranks__ = [2,3,4,5,6,7,8,9,10,"J","Q","K","A"] __suites__ = ["Clubs","Diamods","Hearts","Spades"] class Card(): def __init__(self,suite,rank): if suite in __suites__ and rank in __ranks__: self.suite = suite self.rank = rank else: raise ValueError("Cards need to be instansiated with names from __ranks__ and __suites") def __gt__(self,other): return self._compare_cards_(other,-1) def __lt__(self,other): return self._compare_cards_(other,1) def __ge__(self,other): return self._compare_cards_(other,-1) or self.__eq__(other) def __le__(self,other): return self._compare_cards_(other,1) or self.__eq__(other) def __eq__(self,other): return self._compare_cards_(other,0) def __ne__(self,other): return not self.__eq__(other) def _compare_cards_(self,other,expect): rank_comp = self._compare_ranks_(other.rank,self.rank) if rank_comp == 0: return self._compare_suites_(other.suite,self.suite) == expect return rank_comp == expect def _compare_ranks_(self,rank1,rank2): return self._compare_attributes_("rank",rank1,rank2) def _compare_suites_(self,suite1,suite2): return self._compare_attributes_("suite",suite1,suite2) def _compare_attributes_(self,name,attr1,attr2): attr_list = eval("__{}s__".format(name)) if attr_list.index(attr1) < attr_list.index(attr2): return -1 if attr_list.index(attr1) == attr_list.index(attr2): return 0 if attr_list.index(attr1) > attr_list.index(attr2): return 1

__cmp__

我的单元测试(使用pytest):

def __cmp__(self,other):
  rank_comp = self._compare_ranks_(other.rank,self.rank)
  if rank_comp == 0:
    return self._compare_suites_(other.suite,self.suite)
  return rank_comp

1 个答案:

答案 0 :(得分:2)

__cmp__不再存在,因此这不是一种选择。也就是说,您只能实现__eq____lt__,然后实现use the functools.total_ordering decorator来填充其余的内容:

import functools

@functools.total_ordering
class Card:
  ... init here ...
  def __lt__(self,other):
     return self._compare_cards_(other,1)
  def __eq__(self,other):
     return self._compare_cards_(other,0)
  ... no need for le/ge/gt, and you never need ne on Python 3 anyway ...
  ... rest of code ...

如果您可以升级到3.7,则可能要看一下the dataclasses module,它可以非常轻松地处理代码生成以进行相等性和比较,(如果与enum模块结合使用,可以正确地排名)并且免费提供),将完全删除您的大部分自定义代码,仅保留大约六行。