python面对对象编程------4:类基本的特殊方法__str__,__repr__,__hash__,__new__,__bool__,6大比较方法
一:string相关:__str__(),__repr__(),__format__()
str方法更面向人类阅读,print()使用的就是str
repr方法更面对python,目标是希望生成一个放入eval方法就能够执行的python语句字符串
注意,不要一看到format方法就认为他是用来取代%赋值的
*在里format方法可通过后面的!r与!s来指定使用repr还是str,即此时就不是用的format方法了,而是调用的repr或者str
format有两种参数形式:
1:"",此类可以直接用str(...)来返回
2:format(someobject, specification),
e.g:"{0:06.4f}", the 06.4f is the format specification that applies to item 0 of the argument list to be formatted
format很少用到,在此先略过(书61页)
class Hand:
def __init__( self, name, *friends ):
self.name = name
self.friends= list(friends) def __str__( self ):
return ", ".join( map(str, self.friends) ) def __repr__( self ):
return "{__class__.__name__}({self.name!r}, {_cards_str})".format(__class__=self.__class__,_cards_str=", ".join( map(repr, self.friends) ),self=self) a = Hand("pd","DK","Nancy")
print(str(a))
print(repr(a))
# 输出:
# DK, Nancy, yao
# Hand('pd', 'DK', 'Nancy')
__str__&__repr__
二:__hash__(),__eq__()
python有两个hash库,密码学的hashlib,zlib的adler32()与crc32()
对于简单数字这两个库都不用,直接用hash函数就行,hash函数常用于set,dict等定位其中元素
python每个对象都有个id,本质上id是其内存地址,is比较是基于id的,可用id(x)查看其值,而基类object的__hash__方法就是将其id/16取整后作为integer返回:
需要注意的是只有immutable数值类型才能用hash方法,list与dict没有。所以,如果我们创建的是mutable的对象,就让hash函数返回None就行了 __eq__() 方法,用于==对比,是基于hash值的。 对于immutable object,hash返回基于id的变数,eq用id相比就可以了。而mutable object写eq,hash返回None
#使用默认eq与hash
class Card:
insure= False
def __init__( self, rank, suit, hard, soft ):
self.rank= rank
self.suit= suit
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().__init__( "A", suit, 1, 11 )
class FaceCard( Card ):
def __init__( self, rank, suit ):
super().__init__( {11: 'J', 12: 'Q', 13: 'K' }[rank], suit, 10, 10 ) c1 = AceCard( 1, '?' )
c2 = AceCard( 1, '?' ) print(id(c1),id(c2))
print(id(c1)/16,id(c2)/16)
print(hash(c1),hash(c2))
print(c1==c2)
print(c1 is c2)
print( set([c1,c2]) ) # 输出:
# 42444656 42444688
# 2652791.0 2652793.0
# 2652791 2652793
# False
# False
# {AceCard(suit='?', rank='A'), AceCard(suit='?', rank='A')}
使用默认的__hash__与__eq__
由上可以看出:
同一个类参数相同的两个实例其各种比较[id, is, ==, hash,set去重]都不一样
在现实中使用是有问题的,比如这里面如果我们要比较两张牌则这两张应该看为相同,所以我们需要改写其eq方法,让其不基于id来达到目的
#改进版,重写eq与hash
class Card2:
insure= False
def __init__( self, rank, suit, hard, soft ):
self.rank= rank
self.suit= suit
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))
print(id(c1)/16,id(c2)/16)
print(hash(c1),hash(c2)) #变为相等的数字,但是需要注意的是已经不是 id/16
print(c1==c2) #变为True
print(c1 is c2)
print( set([c1,c2]) )
重写__hash__与__eq__
对于mutable object,在这里依然用card做示范,但其实是不贴切的,card应该是immutable的。注意hash返回None的写法
class Card3:
insure= False
def __init__( self, rank, suit, hard, soft ):
self.rank= rank
self.suit= suit
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
# and self.hard == other.hard and self.soft == other.soft __hash__ = None #!!!!!!!!! class AceCard3( Card3 ):
insure= True
def __init__( self, rank, suit ):
super().__init__( "A", suit, 1, 11 ) c1 = AceCard3( 1, '?' )
c2 = AceCard3( 1, '?' ) print(id(c1),id(c2))
print(id(c1)/16,id(c2)/16)
print(hash(c1),hash(c2)) #报错:TypeError: unhashable type: 'AceCard3'
print(c1==c2) #True
print(c1 is c2)
print( set([c1,c2]) ) #报错:TypeError: unhashable type: 'AceCard3',由于不能hash,自然不能用于set数据结构
mutable object的__hash__与_eq__
对于mutable object,若想对其实例进行数值分析,
可以写一个immutable的子类,将实例传入后完全copy下来,再对copy份进行写hash处理:
如下面的Hand类,可以写一个不可变的FrozenHand类来对其进行hash数值处理
class Hand:
def __init__( self, dealer_card, *cards ):
self.dealer_card= dealer_card
self.cards= list(cards)
def __str__( self ):
return ", ".join( map(str, self.cards) )
def __repr__( self ):
return "{__class__.__name__}({dealer_card!r}, {_cards_str})".format(__class__=self.__class__,_cards_str=", ".join( map(repr, self.cards) ),**self.__dict__ )
def __eq__( self, other ):
return self.cards == other.cards and self.dealer_card ==other.dealer_card
__hash__ = None import sys
class FrozenHand( Hand ):
def __init__( self, *args, **kw ):
if len(args) == 1 and isinstance(args[0], Hand):
# Clone a hand
other= args[0]
self.dealer_card= other.dealer_card
self.cards= other.cards
else:
# Build a fresh hand
super().__init__( *args, **kw )
def __hash__( self ):
h= 0
for c in self.cards:
h = (h + hash(c)) % sys.hash_info.modulus
return h stats = defaultdict(int)
d= Deck() #Deck是一堆牌
h = Hand( d.pop(), d.pop(), d.pop() )
h_f = FrozenHand( h )
stats[h_f] += 1
mutable object的hash处理
三:__bool__
使用:
if xxx:
... #True
else:
... #False
python认为为False的情况:
1:False
2: 0
3:空:‘’,【】,(),{}
注:自带的bool函数可用于测定并返回True还是False,
如 bool(0),bool([]),bool('')都返回False
#对于Deck类,添加__bool__方法:
def __bool__( self ):
return bool( self._cards ) #如果是继承 list 类,可能如下书写:
def __bool__( self ):
return super().__bool__( self )
__bool__
四:6大比较方法
x<y calls x.__lt__(y)
x<=y calls x.__le__(y)
x==y calls x.__eq__(y)
x!=y calls x.__ne__(y)
x>y calls x.__gt__(y)
x>=y calls x.__ge__(y)
class BlackJackCard_p:
def __init__( self, rank, suit ):
self.rank= rank
self.suit= suit def __lt__( self, other ):
print( "Compare {0} < {1}".format( self, other ) )
return self.rank < other.rank def __str__( self ):
return "{rank}{suit}".format( **self.__dict__ ) >>> two = BlackJackCard_p( 2, '?' )
>>> three = BlackJackCard_p( 3, '?' )
>>> two < three
Compare 2? < 3? (*)
True
>>> two > three (*)
Compare 3? < 2?
False
>>> two == three
False
>>> two <= three
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: BlackJackCard_p() <= BlackJackCard_p()
用扑克牌来测试__lt__
由(*)看出: two < three的比较时用的是two.__lt__(three)
two>three由于没有__gt__(),用的是three.__lt__(two)
由于这种机制,我们可以只提供四种方法来包含上面六种:
__eq__(), __ne__(), __lt__(), __le__(). 1:同类实例比较
class BlackJackCard:
def __init__( self, rank, suit, hard, soft ):
self.rank= rank
self.suit= suit
self.hard= hard
self.soft= soft
def __lt__( self, other ):
if not isinstance( other, BlackJackCard ):
return NotImplemented
return self.rank < other.rank
def __le__( self, other ):
try:
return self.rank <= other.rank
except AttributeError:
return NotImplemented
def __gt__( self, other ):
if not isinstance( other, BlackJackCard ):
return NotImplemented
return self.rank > other.rank
def __ge__( self, other ):
if not isinstance( other, BlackJackCard ):
return NotImplemented
return self.rank >= other.rank
def __eq__( self, other ):
if not isinstance( other, BlackJackCard ):
return NotImplemented
return self.rank == other.rank and self.suit == other.suit #比较==时多了对于suit的检查,而比较大小时只比较了rank
def __ne__( self, other ):
if not isinstance( other, BlackJackCard ):
return NotImplemented
"""
注意其上实现的六个比较方法中有两种检验方式:
1:explicit的用isinstance检验是不是BlackJackCard的类实例
2:implicit的用try语句,此种除非是某个类刚好有rank属性才会发生比较,
实际上第二种方法更好,因错出现刚好有rank属性的类又用来比较的概率十分小,而可以用来扩展为别的纸牌游戏的牌与之的比较
"""
>>> two = card21( 2, '?' )
>>> three = card21( 3, '?' )
>>> two_c = card21( 2, '?' ) >>> two == two_c
False
>>> two.rank == two_c.rank
True
>>> two < three
True
>>> two_c < three
True
>>> two < 2 #报错是因为__lt__()方法用isinstance检验了类型,非同类就报错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: Number21Card() < int()
>>> two == 2 #此地没有报错是因为遇到NotImplemented,python会交换他们.在此即是变成int.__eq__()
False
同类实例比较的实现
2:异类实例比较
#下面主要是用isinstance来判断相应的可能的异类的类型,再做处理
class Hand:
def __init__( self, dealer_card, *cards ):
self.dealer_card= dealer_card
self.cards= list(cards)
def __str__( self ):
return ", ".join( map(str, self.cards) )
def __repr__( self ):
return "{__class__.__name__}({dealer_card!r}, {_cards_str})".format(__class__=self.__class__,_cards_str=", ".join( map(repr, self.cards) ),**self.__dict__ )
def __eq__( self, other ):
if isinstance(other,int):
return self.total() == other
try:
return (self.cards == other.cards and self.dealer_card == other.dealer_card)
except AttributeError:
return NotImplemented
def __lt__( self, other ):
if isinstance(other,int):
return self.total() < other
try:
return self.total() < other.total()
except AttributeError:
return NotImplemented
def __le__( self, other ):
if isinstance(other,int):
return self.total() <= other
try:
return self.total() <= other.total()
except AttributeError:
return NotImplemented
__hash__ = None
def total( self ):
delta_soft = max( c.soft-c.hard for c in self.cards )
hard = sum( c.hard for c in self.cards )
if hard+delta_soft <= 21:
return hard+delta_soft
return hard >>> two = card21( 2, '?' )
>>> three = card21( 3, '?' )
>>> two_c = card21( 2, '?' )
>>> ace = card21( 1, '?' )
>>> cards = [ ace, two, two_c, three ]
>>> h= Hand( card21(10,'?'), *cards )
>>> print(h)
A?, 2?, 2?, 3?
>>> h.total()
18
>>> h2= Hand( card21(10,'?'), card21(5,'?'), *cards )
>>> print(h2)
5?, A?, 2?, 2?, 3?
>>> h2.total()
13
>>> h < h2
False
>>> h > h2
True
>>> h == 18
True
>>> h < 19
True
>>> h > 17
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: Hand() > int()
异类实例的比较
五:immutable object的__new__
首先说明为何讲immutable object的__new__,因为mutable object可以直接在__init__中加入新参数而immutable object是不行的:
# 可变对象:
class cL(list):
def __init__(self,value,mutable):
super().__init__(value)
self.mutable = mutable
aha = cL([2,3,4],'mumu')
#注意此处的value参数,用help(list)可看到:list(iterable) -> new list initialized from iterable's items
print(aha,aha.mutable)
# 输出:[2, 3, 4] mumu,可见多了个mutable属性
继承mutable object后添加属性
__new__()默认就是staticmethod,不需要写@satticmethod
对于不可变对象的子类并不能够直接通过__init__方法创造更多的属性,只有通过__new__方法才行
__new__( cls, *args, **kw ).
cls:即将要实例化的类,此参数在实例化时由Python解释器自动提供
*arg & **kw: with the exception of the cls argument, will be passed to __init__() as part of the standard Python behavior.
__new__必须要有返回值,返回实例化出来的实例,且在后一步的__init__方法中就是对这个返回的实例进行操作
默认的__new__()方法调用的是super().__new__(cls)
class Float_Units( float ):
def __new__( cls, value, unit ):
obj= super().__new__( cls, value ) #实例化父类object,并用value初始化
obj.unit= unit #给父类object添加了属性unit,这样由于继承关系也就有了此属性
return obj #返回实例
speed= Float_Units( 6.5, "knots" )
print(speed)
print(speed.unit)
# 输出:
# 6.5
# knots 可见,能够赋值value以及添加属性unit
__new__为immutable object添加属性
python面对对象编程------4:类基本的特殊方法__str__,__repr__,__hash__,__new__,__bool__,6大比较方法的更多相关文章
- python面对对象编程----2:__init__
面对对象编程估计我们最早接触到的就是__init__了,也就是实例的初始化处理过程: 1:来看看最基础的__init__ class Card(object): #抽象类Card,并不用于实例化 de ...
- python面对对象编程----------7:callable(类调用)与context(上下文)
一:callables callables使类实例能够像函数一样被调用 如果类需要一个函数型接口这时用callable,最好继承自abc.Callable,这样有些检查机制并且一看就知道此类的目的是c ...
- python面对对象编程---------6:抽象基类
抽象基本类的几大特点: 1:要定义但是并不完整的实现所有方法 2:基本的意思是作为父类 3:父类需要明确表示出那些方法的特征,这样在写子类时更加简单明白 用抽象基本类的地方: 1:用作父类 2:用作检 ...
- python面对对象编程-------5:获取属性的四种办法:@property, __setattr__(__getattr__) ,descriptor
一:最基本的属性操作 class Generic: pass g= Generic() >>> g.attribute= "value" #创建属性并赋值 > ...
- python面对对象编程中会用到的装饰器
1.property 用途:用来将对像的某个方法伪装成属性来提高代码的统一性. class Goods: #商品类 discount = 0.8 #商品折扣 def __init__(self,nam ...
- python面对对象编程----1:BlackJack(21点)
昨天读完了<Mastering Object-oriented Python>的第一部分,做一些总结. 首先,第一部分总过八章,名字叫Pythonic Classes via Specia ...
- python面对对象编程------3:写集合类的三种方法
写一个集合类的三种方法:wrap,extend,invent 一:包装一个集合类 class Deck: def __init__( self ): self._cards = [card6(r+1, ...
- 16、python面对对象之类和继承
前言:本文主要介绍python面对对象中的类和继承,包括类方法.静态方法.只读属性.继承等. 一.类方法 1.类方法定义 使用装饰器@classmethod装饰,且第一个参数必须是当前类对象,该参数名 ...
- 15、python面对对象之类和对象
前言:本文主要介绍python面对对象中的类和对象,包括类和对象的概念.类的定义.类属性.实例属性及实例方法等. 一.类和对象的概念 问题:什么是类?什么是实例对象? 类:是一类事物的抽象概念,不是真 ...
随机推荐
- Subversion 1.7 Eclipse integration in Ubuntu12(转载)
原文链接:http://steveliles.github.io/subversion_1_7_eclipse_integration_in_ubuntu.html Getting Subversio ...
- centos+nginx+uwsgi+virtualenv+flask 多站点环境搭建
环境: centos x64 6.6 nginx 1.6.2 python 2.7.9 uwsgi 2.0.9 virtualenv 12.0.5 flask 0.10.1 正文: 1.安装nginx ...
- storm接入metaq时类不兼容错误 无法初始化MonitorLog
在实际的项目中,需要storm从metaq中读取数据,一开始就有日志问题,查到是storm/lib中的log4j-over-slf4j和slf4j-api.jar包的不兼容导致的,这些日志包使用时必须 ...
- NET Core 数据保护2
ASP.NET Core 数据保护(Data Protection 集群场景)[下] 前言 接[中篇],在有一些场景下,我们需要对 ASP.NET Core 的加密方法进行扩展,来适应我们的需求, ...
- 基于jsp+servlet图书管理系统之后台用户信息修改操作
上一篇的博客写的是查询操作,且附有源码和数据库,这篇博客写的是修改操作,附有从头至尾写的代码(详细的注释)和数据库! 此次修改操作的源码和数据库:http://download.csdn.net/de ...
- spinner 下拉框控件
spinnerMode=dropdown时,为下拉模式spinnerMode=dialog时,会在界面中间弹出Android:popupBackground=”#f0000000”,可以去除spinn ...
- win2k,XP下用setupapi.dll自动安装Driver
win2k,XP下用setupapi.dll自动安装Driver 在驱网看到54cndr 写的这篇文章,虽然自己一直都用Installshield,但还是觉得这个也是一个很好的思路,故摘录在此. 用s ...
- 【转】整理一下Android中的ListView
原文网址:http://sunbofu.blog.51cto.com/6431507/1280441 Android中的listview目测是一个使用频率很高的组件,所以今天来总结一下listview ...
- URL图片预览(createObjectURL)
1.说明 1)createObjectURL 作用:创建url(creates a URL for the specified object); 语法:var url = URL.createObj ...
- cf701B Cells Not Under Attack
Vasya has the square chessboard of size n × n and m rooks. Initially the chessboard is empty. Vasya ...