如何在python中实现一个可以比较、排序等的类
我正在尝试编写一个Card类,我想确保我可以对其使用比较运算符,以及使用我的如何在python中实现一个可以比较、排序等的类,python,Python,我正在尝试编写一个Card类,我想确保我可以对其使用比较运算符,以及使用我的Card对象的max、min排序列表 我读到为了实现这一点,我只需要实现\uuucmp\uuuuuuuuuuuuu,但是当我这样做的时候,我的单元测试就不会通过,所以我最终实现了所有的比较魔术方法\uuuuugt\uuuuuuuuu,\uueq\uuuuuuuuuuu,等等 如果可能的话,我想消除代码中的膨胀,并删除\uuu cmp\uuu所需的所有比较方法 我使用的是Python 3.5 Anaconda发行版 这是我
Card
对象的max、min排序列表
我读到为了实现这一点,我只需要实现\uuucmp\uuuuuuuuuuuuu
,但是当我这样做的时候,我的单元测试就不会通过,所以我最终实现了所有的比较魔术方法\uuuuugt\uuuuuuuuu
,\uueq\uuuuuuuuuuu
,等等
如果可能的话,我想消除代码中的膨胀,并删除\uuu cmp\uuu
所需的所有比较方法
我使用的是Python 3.5 Anaconda发行版
这是我当前的实现:
__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
我的单元测试(使用pytest):
导入pytest
从game.deck导入卡
def测试卡排名可以比较()
十张黑桃=牌(“黑桃”,10)
黑桃杰克=牌(“黑桃”,“J”)
断言十个铁锹<杰克铁锹
断言黑桃杰克>黑桃十
断言十张黑桃=十张黑桃
def测试卡套件可以安装():
十张黑桃=牌(“黑桃”,10)
十个俱乐部=卡片(“俱乐部”,10)
断言十张黑桃>十张梅花
断言十支梅花<十支黑桃
断言十个黑桃>=十个梅花
断言十个俱乐部不再存在,因此这不是一个选项。也就是说,您只能实现\uuuu eq\uuu
和\uu lt\uuuu
,然后填充其余部分:
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,您可能想看看哪一个可以非常轻松地处理代码生成以实现相等和比较,哪一个(如果与enum
模块结合使用,可以免费对您的等级和套装进行正确排序)将完全删除大部分自定义代码,只留下六行左右。是您发布的实际缩进吗?如果是这样的话,您没有向Card
类添加特殊方法,您只是创建了一组从未被调用过的函数。\uu cmp\uu
在Python3中消失了。权力决定了你必须以臃肿的方式做事。我个人没有就这个决定咨询过我,如果我是的话,我会投反对票的。还有,为什么你要如此努力地与Python作斗争,而不是像预期的那样使用它?你的代码会简单得多。旁注:卡片上有“套装”,而不是“套装”;多元化,仍然是“套装”,而不是“套装”。只有当出现e
时,它指的是“适合的”卡片,但这纯粹是-ed
后缀,而不是单词本身的一部分。@mypetlion:除了NumPy动机之外,如果不在旧API中对比较进行排序,就不可能实现相等比较。此外,要求每个等式测试都计算顺序会影响性能。丰富的比较可能需要更多的代码,但好处是实实在在的。即使对于3.6,您也可以使用dataclasses backport,或是启发它的第三方库attrs。
import pytest
from game.deck import Card
def test_card_rank_can_be_compared():
ten_of_spades = Card("Spades",10)
jack_of_spades = Card("Spades","J")
assert ten_of_spades < jack_of_spades
assert jack_of_spades > ten_of_spades
assert ten_of_spades <= jack_of_spades
assert jack_of_spades >= ten_of_spades
def test_card_suite_can_be_comapred():
ten_of_spades = Card("Spades",10)
ten_of_clubs = Card("Clubs",10)
assert ten_of_spades > ten_of_clubs
assert ten_of_clubs < ten_of_spades
assert ten_of_spades >= ten_of_clubs
assert ten_of_clubs <= ten_of_spades
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 ...