我正在尝试编写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
答案 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
模块结合使用,可以正确地排名)并且免费提供),将完全删除您的大部分自定义代码,仅保留大约六行。