第二章 與Python的悟性陳繼承----基本特殊方法.
python中有有一些特殊的方法,它們?cè)试S我們的類和python更好的集成
-
__repr__()
: __str__()
__format__()
__hash__()
__bool__()
__bytes__()
__lt__()
__le__()
__eq__()
__ne__()
__gt__()
__ge__()
__new__()
__del__()
2.1 __repr__()
和__str__()
方法
- 通常
str()
方法表示的對(duì)象對(duì)用戶更加友好.這個(gè)方法是有對(duì)象的__str__()
方法實(shí)現(xiàn)的.
什么時(shí)候重寫 __str__()
跟__repr__()
- 非集合對(duì)象: 一個(gè)不包括其他集合對(duì)象的'簡(jiǎn)單'對(duì)象,這類對(duì)象格式通常不會(huì)特別復(fù)雜
- 集合對(duì)象:一個(gè)包括集合的對(duì)象,這類對(duì)象的格式化會(huì)非常復(fù)雜.
非集合對(duì)象的__repr__()
和__str__()
問(wèn)題1: 什么是集合?
class Card(object):
def __init__(self, rank, suit):
self.suit = suit
self.rank = rank
self.hard, self.soft = self._points()
def __repr__(self):
return '{__class__.__name__}(suit = {suit!r} , rank = {rank!r})'.format(
__class__=self.__class__, **self.__dict__
)
def __str__(self):
return '{rank}{suit}'.format(**self.__dict__)
class NumberCard(Card):
def _points(self):
return int(self.rank), int(self.rank)
x = NumberCard('2', '?')
# 注意下面是重寫后的
print(str(x)) # 2?
print(x) # 2?
print(repr(x)) # NumberCard(suit = '?' , rank = '2')
__format__()
方法
注意:‘{0!r}'.format()
和'{0!s}'.format()
并不會(huì)調(diào)用__format__()
方法,它們會(huì)調(diào)用__repr__()
或者__str__()
.
__hash__()
方法
內(nèi)置hash()
函數(shù)調(diào)用了__hash__()
方法.哈希是一種將復(fù)雜的值簡(jiǎn)化為小整數(shù)的計(jì)算方式.
python有兩個(gè)哈希庫(kù):
- hashlib
- zip 有兩個(gè)搞笑的哈希函數(shù)
adler32()
和crc32()
hasd()函數(shù)主要被用來(lái)創(chuàng)建set,forzenset,dict這些集合類的鍵.這些集合利用了不可變對(duì)象的哈希值來(lái)高效的查找集合中的對(duì)象
決定hash的對(duì)象
并非每個(gè)對(duì)象都需要提供一個(gè)哈希值,尤其是,當(dāng)我們創(chuàng)建一個(gè)包含有狀態(tài),可改變對(duì)象的類時(shí).這類不應(yīng)該返回哈希值,__hash__
的定義 應(yīng)該是None
等價(jià)比較有三個(gè)層次:
- 哈希值相等:意味著兩個(gè)結(jié)果可能相等.哈希值是判斷兩個(gè)對(duì)象有可能相等的快捷方式,如果哈希值不同,兩個(gè)對(duì)象不可能相等,也不可能是同一個(gè)對(duì)象.
- 比較結(jié)果相等:意味著兩個(gè)對(duì)象的哈希值已經(jīng)是相等的尤仍,這個(gè)比較用的是
==
運(yùn)算符.如果結(jié)果相等,那么兩個(gè)對(duì)象的有可能是同一個(gè). - IDD 相等:這意味著兩個(gè)對(duì)象是同一個(gè)對(duì)象,它們的哈希值仙童,并且使用
==
的比較結(jié)果相等,這個(gè)比較是用的是is運(yùn)算符.
**基本哈希法(Fundametal Law of Hash):比較相等的對(duì)象的哈希值一定相等.
有關(guān)不可變對(duì)象和繼承的默認(rèn)行為
class Card(object):
def __init__(self, rank, suit, hard, soft):
self.suit = suit
self.rank = rank
self.hard = hard
self.soft = soft
def __repr__(self):
return '{__class__.__name__}(suit = {suit!r} , rank = {rank!r})'.format(
__class__=self.__class__, **self.__dict__
)
def __str__(self):
return '{rank}{suit}'.format(**self.__dict__)
class NumberCard(Card):
def __init__(self, rank, suit):
super().__init__(str(rank), suit, rank, rank)
class AceCard(Card):
def __init__(self, rank, suit):
super(AceCard, self).__init__("A", suit, 1, 11)
class FaceCard(Card):
def __init__(self, rank, suit):
super(FaceCard, self).__init__({11: 'J',
12: 'Q',
13: 'K'}[rank], suit, 10, 10)
c1 = AceCard(1,'?')
c2 = AceCard(1,'?')
print(id(c1),id(c2)) # 52067024 52067120
id()
值不同意味著是不同的對(duì)象.
**is測(cè)試
基于id()
的值,哈希值根據(jù)id()
值來(lái)計(jì)算的`
重載不可變對(duì)象
下面是一個(gè)重載了__hash__()
和__eq__()
定義的簡(jiǎn)單類.
class Card2(object):
def __init__(self, rank, suit, hard, soft):
self.suit = suit
self.rank = rank
self.hard = hard
self.soft = soft
def __repr__(self):
return '{__class__.__name__}(suit = {suit!r} , rank = {rank!r})'.format(
__class__=self.__class__, **self.__dict__
)
def __str__(self):
return '{rank}{suit}'.format(**self.__dict__)
def __eq__(self, other):
return self.suit == other.suit and self.rank == other.rank
def __hash__(self):
return hash(self.suit) ^ hash(self.rank)
class AceCard2(Card2):
insure = True
def __init__(self, rank, suit):
super().__init__("A", suit, 1, 11)
c1 = AceCard2(1, '?')
c2 = AceCard2(1, '?')
print(id(c1), id(c2)) # id 是不相同的
print(c1 is c2) # False
print(hash(c1), hash(c2)) # hash是相同的
print(c1 == c2) # True
print(set([c1,c2])) # {AceCard2(suit = '?' , rank = 'A')}
重載可變對(duì)象
下面的類層級(jí)結(jié)構(gòu)中,我們沖在了可變對(duì)象的 __hash__()
和__eq__()