Python扑克手牌比较程序__str__与__repr__方法实现求助
魔法方法实现方案
__str__ 面向普通用户,输出直观易读的展示内容;__repr__ 面向开发者,输出可直接执行、重建对应对象的表达式:
Card 类魔法方法
__str__:输出「牌面缩写+花色符号」,比如A♥、10♤、3♦__repr__:输出可直接实例化Card的表达式,比如Card(suit='hearts', name='ace')
实现代码:
def __str__(self): # 牌面名称转缩写 name_abbr = { 'ace': 'A', 'king': 'K', 'queen': 'Q', 'jack': 'J' }.get(self.name, self.name) return f"{name_abbr}{self.card_suits[self.suit]}" def __repr__(self): return f"Card(suit={self.suit!r}, name={self.name!r})"
Hand 类魔法方法
__str__:输出所有牌的列表+当前手牌等级,比如[10♤, J♤, Q♤, K♤, A♤] 皇家同花顺__repr__:输出可直接实例化Hand的表达式
实现代码:
def __str__(self): # 先获取手牌等级名称 rank_map = [ (self.royal_flush, "皇家同花顺"), (self.straight_flush, "同花顺"), (self.four_of_a_kind, "四条"), (self.full_house, "葫芦"), (self.flush, "同花"), (self.straight, "顺子"), (self.three_of_kind, "三条"), (self.two_pair, "两对"), (self.one_pair, "一对"), (lambda: True, "高牌") ] for check_func, rank_name in rank_map: if check_func(): break return f"{[str(c) for c in self.cards]} {rank_name}" def __repr__(self): return f"Hand(card_list={self.cards!r})"
代码优化建议
- 给
Card.__init__加非法参数校验:当前代码如果传入非法花色,不会给self.suit赋值,后续调用会抛出属性错误,建议非法参数直接抛出明确的ValueError - 用
functools.total_ordering装饰器简化比较方法:只要实现__lt__和__eq__,其余大小比较方法会自动生成,无需手动编写__gt__ - 弃用冗余的getter方法:Python不需要像Java一样编写
get_value、get_suit这类方法,直接访问实例属性即可,代码更简洁 - 优化顺子判断逻辑:当前代码不支持
A-2-3-4-5这类最小顺子,可加特殊判断处理 - 用
collections.Counter优化牌数统计逻辑:当前_pair、_of_a_kind方法的实现效率低、可读性差,用Counter统计牌面出现次数会清晰很多 - 优化手牌强度比较逻辑:当前
determine_strength只加了基础分+高牌,同牌型下无法区分大小(比如两对A,A,K,K,2和A,A,Q,Q,J,按现有逻辑得分相同,实际前者更大),建议把得分拆成「基础分+牌组权重元组」比较,同牌型下按元组优先级比较
修改后完整可运行代码
import random from functools import total_ordering from collections import Counter @total_ordering class Card(object): card_values = {'ace' : 13, 'king' : 12, 'queen' : 11, 'jack' : 10, '10' : 9, '9' : 8, '8' : 7, '7' : 6, '6' : 5, '5' : 4, '4' : 3, '3' : 2, '2' : 1} card_suits = {'spades' : u'♤', 'diamonds' : u'♦', 'clubs': u'♧', 'hearts' : u'♥'} name_abbr = {'ace': 'A', 'king': 'K', 'queen': 'Q', 'jack': 'J'} def __init__(self, suit, name): if name not in self.card_values: raise ValueError(f"非法牌面,合法值为{list(self.card_values.keys())}") if suit not in self.card_suits: raise ValueError(f"非法花色,合法值为{list(self.card_suits.keys())}") self.name = name self.value = self.card_values[name] self.suit = suit def __lt__(self, other): return self.value < other.value def __eq__(self, other): return isinstance(other, Card) and (self.value == other.value) and (self.suit == other.suit) def __str__(self): abbr = self.name_abbr.get(self.name, self.name) return f"{abbr}{self.card_suits[self.suit]}" def __repr__(self): return f"Card(suit={self.suit!r}, name={self.name!r})" def same_suit(self, other): return self.suit == other.suit class Hand(object): def __init__(self, card_list): assert len(card_list) == 5, "手牌必须为5张牌" self.cards = sorted(card_list) # 提前统计牌面出现次数,避免重复计算 self.value_counts = Counter(c.value for c in self.cards) self.count_values = sorted(self.value_counts.values(), reverse=True) self.sorted_values = sorted(self.value_counts.keys(), reverse=True) def determine_strength(self): # 返回(基础分, 权重元组),直接比较元组大小即可判断手牌强弱 if self.royal_flush(): return (10, ()) elif self.straight_flush(): return (9, (self.sorted_values[0],)) elif self.four_of_a_kind(): four_val = next(k for k,v in self.value_counts.items() if v==4) kicker = next(k for k,v in self.value_counts.items() if v==1) return (8, (four_val, kicker)) elif self.full_house(): three_val = next(k for k,v in self.value_counts.items() if v==3) pair_val = next(k for k,v in self.value_counts.items() if v==2) return (7, (three_val, pair_val)) elif self.flush(): return (6, tuple(self.sorted_values)) elif self.straight(): return (5, (self.sorted_values[0],)) elif self.three_of_kind(): three_val = next(k for k,v in self.value_counts.items() if v==3) kickers = sorted([k for k,v in self.value_counts.items() if v==1], reverse=True) return (4, (three_val, *kickers)) elif self.two_pair(): pairs = sorted([k for k,v in self.value_counts.items() if v==2], reverse=True) kicker = next(k for k,v in self.value_counts.items() if v==1) return (3, (*pairs, kicker)) elif self.one_pair(): pair_val = next(k for k,v in self.value_counts.items() if v==2) kickers = sorted([k for k,v in self.value_counts.items() if v==1], reverse=True) return (2, (pair_val, *kickers)) return (1, tuple(self.sorted_values)) def flush(self): suit = self.cards[0].suit return all(c.suit == suit for c in self.cards) def straight(self): values = sorted(c.value for c in self.cards) # 普通顺子判断 if values == list(range(values[0], values[0]+5)): return True # 特殊处理A-2-3-4-5顺子 return values == [1,2,3,4,13] def straight_flush(self): return self.straight() and self.flush() def royal_flush(self): return self.straight_flush() and self.cards[-1].name == 'ace' and self.cards[0].value == 9 def one_pair(self): return self.count_values[0] == 2 def two_pair(self): return self.count_values[0] == 2 and self.count_values[1] == 2 def three_of_kind(self): return self.count_values[0] == 3 def four_of_a_kind(self): return self.count_values[0] == 4 def full_house(self): return self.count_values[0] == 3 and self.count_values[1] == 2 def __str__(self): rank_map = [ (self.royal_flush, "皇家同花顺"), (self.straight_flush, "同花顺"), (self.four_of_a_kind, "四条"), (self.full_house, "葫芦"), (self.flush, "同花"), (self.straight, "顺子"), (self.three_of_kind, "三条"), (self.two_pair, "两对"), (self.one_pair, "一对"), (lambda: True, "高牌") ] for check_func, rank_name in rank_map: if check_func(): break return f"{[str(c) for c in self.cards]} {rank_name}" def __repr__(self): return f"Hand(card_list={self.cards!r})"
内容的提问来源于stack exchange,提问作者user17567573
相关产品推荐
相关产品推荐

