析构方法
某对象 借用了操作系统的资源 还要通过 析构方法 归还回去 :
归还的包括 文件资源 网络资源
在清楚一个对象 在内存中的使用的时候 , 会触发 这个对象所在类中的析构方法
释放一个空间 之前执行的
_ _del_ _ del A的对象
del 类名() 即对象 会自动触发这个方法
e.g
class File:
def __init__( self , file_path ):
self . f=open( file_path ) #创建一个文件的句柄
def read( self ) :
self . f . read( 1024 )
def __del__(self) : #是去归还 / 释放一些在创建对象的时候借用的一些资源
self . f.close ()
f =File(' 文件名 ')
f . read()
1. 在 del 对象 的时候执行 程序员触发的
2. 在python解释器的垃圾回收机制 回收这个对象 所占的内存的时候 Python 自动触发的
不管是主动还是被动 这个f 对象 总会被清理掉
被清理掉 就会触发 _ _del__方法, 触发这个方法就会归还 操作系统的 文件资源
python 解释器在内部就能搞定的事儿 :
先申请一块空间 ===> 操作系统分配给你的 在这块空间中所有的事都归你的 python解释器来管
f=open('文件') # python ====> 操作系统===>硬件里边 得文件 ===> 文件的操作符( 文件句柄 )
f.close() 关闭的是操作系统 从硬件里边 拿出来的那个文件 即 文件资源还给了 操作系统
del f # 删除的是 文件的 那个空间里边的 变量和方法
item 系列
item 系列 和 对象[ ] 访问值有联系
在内置模块中 : 有一些特殊 的方法要求 对象必须 实现__getitem__ __setitem__才能使用
对象[ ] ==== item
__getitem__ obj[ ' eejdj ' ]
__setitem__ obj[ ' hhfbbf ' ] = '' kjkj ''
__delitem__ del obj[ ' jkhh ' ]
e.g
obj={ ' k ' : ' v ' }
print( obj ) ===> { ' k ' : ' v ' }
print ( obj[ ' k ' ] ) ===> v 这样可以实现
class B:
def __getitem__( self , item):
print( '执行啦' , item )
return ' bbb '
def __setitem__( self , key,value ):
print( key,value )
b=B()
print(b[ 'a' ]) #调用了 __getitem__ 拿到 返回值 bbb
print (b [ 'k'] ) # 调用了 __getitem__ 拿到 返回值 bbb
b[ 'k' ] = ' value ' #调用了 __setitem__ 执行拿不到返回值
print ( b['k'] ) # 调用 __getitem __...
class B:
def __getitem__(self , item):
return getattr( self,item)
def __set item__( self, key,value):
setattr( self,key,value)
def __delitem__(self,key):
delattr(self,key)
b=B()
b[ 'k1' ]='v' # 先执行 __set item__ 将 k1 传给 key v 传给 value
print(b.__dict__) ===> { 'k1' : ' v' }
print( b[ ' k1' ] ) # 执行__getitem__ 将k1传给 item 拿到返回值 v
del b['k1] # 执行__delitem__ 将键值对删除
若 __delitem__方法下边是 pass 没有执行删除的步骤 则不会删除
print( b[ ' k1' ] ) ====> { }
e.g
class B:
def __init__( self , lst ): # 1
self .lst =lst
def __getitem__( self , item ): # 2
return self.lst [ item ]
def __setitem__( self, key, value ): # 3
self . lst [ key ] =value
def __delitem__( self , key ): # 4
self .lst .pop [ key ]
b=B( [ ' 111 ' , '' 222 '' ,'' ccc'' , '' ddd'' ] ) # 执行1
print( b.lst [ 0 ] ) # 执行1 ===> 111
print( b [ 0 ] ) # 执行2 ===> 111
b [ 3 ] = '' alex '' # 执行3
print( b.lst ) # ===> [ ' 111 ' , '' 222 '' ,'' ccc'' , '' alex'' ]
del b[ 2 ] # 执行4
print( b.lst ) ====> [ ' 111 ' , '' 222 '' , '' alex'' ]
hash 方法 hash( obj ) obj内部必须要实现了 __hash__算法
hash 算法: 底层数据结构基于 hash 值寻址的优化操作
hash 是一个算法: 能够把某个要存在内存里的值 通过一系列 计算 , 保证不同值的hash 结果是不一样的
对于同一个值 在多次执行python 代码的时候 hash 值不同
但对同一个值 在同一次执行python代码的时候 hash值永远不变
同一次执行表示 右键单击一个Run就是一次执行
字典的寻址
一个hash值 代表一个内存 因此找的特别快
set 集合去重 原理机制:
先判断hash 值是否一样 , 当hash值一样的时候 再判断 两端值 是否相等 即判断 是否 ==
相当于 当两端的hash 相等的时候 会触发 _ _eq_ _
值相等是最准确的判断值相等的方式 ==
但是 若在集合中采用== 来判断的话, 每次遇到一个值 都会 和之前所有的值都重新比较一次 效率太慢了
而 hash值 是将每个元素的hash 值算好 , 每次遇到一个值都会算哈希值 , 算好不同的 直接放到一个 格子当中
再算第二个 不一样也放到 一个空格子中,
当遇到两个hash值一样的时候 , 即 格子中有 元素的时候 就会判断这两个值是否 == ,
若 == 则覆盖 否则再放到一个新的格子中
_ _eq_ _ 和 == 一样
对象1 == 对象2 : 这个语法 完全和__eq__一样 触发的是 __eq__这个方法
e.g
class A:
def __init__( self ,name,age ):
self.name=name
self.age=age
def __eq__(self,other):
if self.name==other.age and self.name==other.name:
return True
a=A('' alex '' , 83)
aa=A(''alex '' , 83)
aaa=A('' alex'',83)
print(aaa==a==aa) =====> True
一道面试题
给着1000个员工去重 姓名和性别相同的算是 同一个人 去掉
class Employee:
def __init__(self,name,age,sex,partment): # 封装几个信息属性
self.name=name
self.age=age
self.sex=sex
self.partment=partment
def __hash__(self): # 将 姓名和性别的hash值算出来
return hash("%s%s"%(self.name,self.sex))
def __eq__(self,other): # 判断 姓名和性别相同的 值是否一样
if self.name==other.name and self.sex==other.sex
return True
employ_lst=[ ] # 将 姓名和性别相同的添加到列表总
for i in range(200):
employ_lst.append(Employee("alex",i,"name",'python'))
for i in range(200):
employ_lst.append(Employee("wusir",i,"njhgh",'python'))
for i in range(200):
employ_lst.append(Employee("wtaibaiir",i,"nkogjhgh",'python'))
employ_set=set(employ_lst) # 执行 去重
for person in employ_lst:
print(person.__dict)