python面对对象核心之魔术方法 - - ->dir(), 运算符重载,可视化,容器
__name__ 类,函数,方法等的名字
__module__ 类定义所在的模块名
__class__ 对象或类所属的类
__bases__ 类的基类元组,顺序为它们在基类列表中出现的顺序
__doc__ 类 函数的字符串,如果没有定义则为None
__mro__ 类的mro ,class.mro() 的 结果保存在__mro__中
__dict__ 类或者实例的属性,可写的字典
查看属性:
__dir__ 返回类或者对象的所有成员名称,dir( )函数就是调用__dir__,如果提供__dir__(),则返回属性的列表,否则会尽量从__dict__属性中收集信息
如果dir( )参数包含方法__dir__()方法将被调用,如果不包含__dir__(),改方法将最大限度的收集参数信息
dir()对于不同类型的对象具有不同的行为
如果对象是模块对象,列表包含模块的属性名
如果对象是类型或者类对象,列表包含类的属性名,及它的基类的属性名
否则,列表包含对象的属性名,它的类的属性名,和类的基类的属性名
class Animal:
x = 123
def __init__(self,name):
self.name = name
self.__age = 10
self.weight = 20
print('animal Module\'s name ={}'.format(dir(Animal))) #指定模块名词空间内的属性
print('object's__dict ={}'.format(sorted(object.__dict__.keys())) #object的字典
print('Animal's dir() = {}'.format(dir(Animal))) 类Animal的dir()
分类:
创建与销毁
__init__ 与__del__
hash
bool
可视化
运算符重载
容器和大小
可调用对象
上下文管理
反射
描述器
其他
hash
散列,哈希就是得到散列值,哈希可能一样,但是对象不是一个,称为哈希冲突
使用哈希取模法,来得到一个个不同的哈希值
h%n = hash
__hash__ 内建函数hash()调用的返回值,返回一个整数,如果定义这个方法该类的实例就可hash
使用 hash() 相当于调用 **.__hash__( )
__hash__方法只能判断两个值的引用或者值是否相等,但是去重得用__eq__来判断是否他们的内存地址是否一样
__eq__ 对应== 操作符,判断2个对象是否相等,返回bool值
#a == b 等价于 a.__eq__(b) 运算符的实现方法
set集合 会先使用__eq__方法判断值是否一样,如果一样就会去重,即使内存地址一样
__hash__方法只是返回一个hash值作为set的key,但是去重,还需要__eq__来判断2个对象是否相等
hash 值相等,只是hash冲突,不能说明两个对象是相等的
因此,一般来说提供__hash__方法是为了作为set或者dict的key的,所以去重要同时提供__eq__方法
可hash对象必须提供__hash__方法,没有提供的话,isinstance(p1,collections.Hashable)一定为False
去重要提供__eq方法
__bool__ 内建函数bool()或者对象放在逻辑表达式的位置,调用这个函数返回布尔值
没有定义__bool__(),就找__len__()返回长度,非0为真,如果__len__()也没有定义,那么所有实例都返回真
可视化:
方法:
除了print ,str , format之外其他大部分调用的都是__repr__
__repr__ 内建函数repr()对一个对象获取字符串表达式,如果一个类定义了__repr__( )但没有定义__str__,那么在请求该类的实例的‘ 非正式 ’的字符串时也将调用__repr__()
__str__ str()函数,内建函数format、print()函数调用,需要返回对象的字符串表达
运算符重载
operator模块提供以下的特殊方法,可以将实例使用下面的操作符来操作
运算符
|
特殊方法
|
含义
|
<,<=,==,>,>=,!=
|
__lt__,__le__,__eq__,__gt__,__ge__,__ne__
|
比较运算符
|
+,-,*,/,%,//,**,divmod
|
__add__,__sub__,__mul__,__truediv__,__mod__,__floordiv__,__pow__,__divmod__
|
算数运算符,移位,位运算也有对应的方法
|
+=,-=,*=,/=,%=,//=,**=
|
__iadd__,__isub__,__mul__,iturediv__,__imod__,__ifloordiv__,__ipow__
|
|
返回类型,
实现连加(链式编程),返回实例本身
class A:
def __init__(self,x):
self.x = x
def __sub__(self, other):
return self.x - other.x
def __isub__(self, other):
tmp = self.x - other.x
return tmp
def __str__(self):
return str(self.x)
x = A(4)
y = A(5)
print(x - y ,x.__sub__(y))
x-=y
print(x)
习题1:
完成point类设计,实现判断点相等的方法,并完成向量的加法
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def add(self,other): #提供格式化后的追加打印
return Point(self.x+other.x,self.y+other.y)
def __add__(self, other): #运算符重载,会提供 + 号的方法
return (self.x + other.x , self.y + other.y)
def __str__(self): #可视化
return '{},{}'.format(self.x,self.y)
a =Point(1,3)
b =Point(1,1)
point = (a,b)
#print(point[0].add(point[1]))
print(point[0]+point[1])
point(Point(*(point[0]+ point[1])))
print(a==b)
运算符重载应用场景
往往使用面向对象实现的类,需要做大量的运算,而运算符是这种运算在数学上最常见的表达方式,例如,上例中的对 + 进行了运算符重载,实现了Point类的二元操作,重新定义为Point+Point
提供运算符重载,比直接提供加法方法要更加适合该领域内使用者的习惯
int类,基本实现了所有的操作符,可以参考
容器相关方法
方法
|
意义
|
__len__
|
内建输入法len( ),返回对象的长度(>=0的正数),其实即使把对象当做容器类型来看,就如同list或者dict,bool()函数调用的时候,如果没有__bool__()方法,则会看__len__()方法是否存在,存在返回非0为真
|
__iter__
|
迭代容器时,调用,返回一个新的迭代器对象
|
__contains__
|
in成员运算符,没有实现,就调用__iter__方法遍历
|
__getitem__
|
实现self[key]访问,序列对象,key接受整数位索引,或者切片,对于set和dict,key位hashable,key不存在引发KeyError异常
|
__setitem__
|
和__getitem__的访问类似,是设置值的方法
|
__missing__
|
字典使用__getitem__()调用时,key不存在执行该方法
|
练习,将购物车改造成方便操作的容器类
class Cart:
def __init__(self):
self.lst = []
def __len__(self):
return len(self.lst) # 获取长度
def add(self,items): # 追加数据
self.lst.append(self.items)
def __iter__(self): #迭代和in操作
return iter(self.lst)
def __getitem__(self, item): # 根据索引拿数据
return self.lst[item]
def __setitem__(self, key, value): #索引赋值操作
self.lst[key] = value
a =Cart()
print(2 in a) #in
a.lst.append(5) #追加
for i in a: #迭代
print(i)
print(a.lst[0],10) #赋值
print(a.lst[0]) #拿索引取值
可调用对象
python中一切皆对象,函数也不例外
def foo():
print(foo.__module__,foo.__name__)
foo()
等价于 foo.__call__()
函数即对象,对象foo加上(),就等于调用对象的__call__( )方法
可调用对象
方法
|
意义
|
__call__
|
类中的第一个方法,实例就可以向函数一样调用
|
可调用对象,应以一个类,并实例化得到其实例,就可以将其向函数一样调用
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __call__(self, *args, **kwargs): #1-1
return self.x + self.y
a = Point(4,5)
print(a()) # a() = a.__call__(self.x+self.y) 等于调用1-1
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Adder:
def __call__(self, *args): # (*接受参数)
ret =0
for x in args:
ret += x
self.ret = ret
return ret
a =Adder()
print(a(4,5,6))
定义一个斐波那契数列方便调用
class Fib:
def __init__(self):
self.items=[0,1,1]
def __call__(self, x):
if x < 2:
raise Exception('Error')
else:
for i in range(3,x+1):
self.items.append(self.items[i-1]+self.items[i-2]) #直接append进去,这样外部的列表就会保存所有迭代的数据,减少计算次数
return self.items #注意return的位置,等迭代完在return,不然只能迭代一次
def __getitem__(self, index): #设置一个可根据索引拿数据的魔术方法,很方便调用
return self.items[index]
def __len__(self):
return len(self.items)
def __iter__(self):
return iter(self.items)
def __str__(self):
return str(self.items)
a= Fib()
print(a(500))
print(a[8])
print(a.items[8])
print(len(a.items))
print(a)
posted on 2017-11-21 14:37 pythonerLau 阅读(382) 评论(0) 收藏 举报