30.2-魔术方法—实例化(创建)、hash和equal
面对人生各种处境,我们都有选择的能力。面对一件不幸的事件,你可以大发雷霆、怨天尤人,甚至责备所有的人,但事情却不会因为这些而丝毫改变。不幸的事,它会继续地伴着你往后的生活,让你背负着一生的痛苦活下去。相反如果能放下怨恨和惧怕,换一个角度看事情,那么事情也许就不会如想象中那么糟糕

总结:
1.原则上:key相同,集合中才会有去重效果;hash值相同代表在同一个房间;
1. 魔术方法***(非常重要)
在python学习中,往往你会看到有的名称前面和后面都加上了双下划线,例如init、str、doc、new等,这种写法很特别,在python 中由这些名字组成的集合所包含的方法就叫做魔法方法,也叫做特殊方法。魔术方法在类或对象的某些事件出发后会自动执行;
分类:
创建、初始化与销毁;
_init_ 与 _del_
hash
bool
可视化
运算符重载
容器和大小
可调用对象
上下文管理
反射
描述器
其他杂项
Python提供的魔法方法

1.1 实例化
方法 | 意义 |
---|---|
_new_ | 1.实例化一个对象,该方法需要返回一个值,如果该值不是cls的实例,则不会调用 _init_该方法永远都是静态方法 ; 2.返回值可有可无,无返回值时结果为None,3.在方法类返回时,不得采用当前类.new,因为这样会触发无限递归。可采用如下方式之一 |
new 方法的使用:
_new_ 方法很少使用,即使创建了该方法,也会使用 return super()._new_(cls) 基类object的 new 方法来创建实例并返回;语言类编程的时候使用;
class A:pass
class B(A):pass
class C(B):
def __new__(cls,*args,**kwargs):
print(cls)
print(args)
print(kwargs)
return super().__new__(cls) # 返回一个实例new;
# return 'abc'
def __init__(self,name):
self.name = name
print('~~~~~~~~~~~~')
# def __dir__(self):
# return ('a','b','c','d')
# def printdir(self):
# print(dir(),'~~~~~~')
c = C('tom')
print(dir(c.__dict__))
print('-'*79)
print(sorted(dir(c)))
#---------------------------------------------------------------------------------------------------------
<class '__main__.C'>
('tom',)
{}
~~~~~~~~~~~~
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
-------------------------------------------------------------------------------
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']
1.2 hash(门牌号码) _可hash对象;
- hash int为 int本身 ; 非整形(字符、字符串等)为不同的值;值是没有规律;
- hash的幂等性:x不一样, hash 应该不一样;
- hash冲突: 不同的hash算法求值:不同的x求得同样的hash值;
hash 空间充满的情况下,再往里面塞数,一定会出现hash值相同的情况;
类的实例可哈希;
方法 | 意义 |
---|---|
_hash_ | 内建函数 hash() 调用的返回值,返回一个整数。如果定义这个方法该类的实例就可hash。 |
_hash_ == None(类中加) | 类对象不可hash |
class A:pass
class B(A):pass
class C(B):
def __hash__(self): # hash门牌号码;
return hash('abc')
def __init__(self,name):
self.name = name
print('~~~~~~~~~~~~')
# def __dir__(self):
# return ('a','b','c','d')
# def printdir(self):
# print(dir(),'~~~~~~')
c = C('tom')
p = C('peter')
print(dir(c.__dict__))
print('-'*79)
print(hash(c))
print(hash(p))
#-----------------------------------------------------------------
~~~~~~~~~~~~
~~~~~~~~~~~~
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
-------------------------------------------------------------------------------
-8920692834900147942
-8920692834900147942
print(hash(c))
print(hash(p))
print('-'*60)
print((c,p))
print([c,p])
print({c,p}) # hash值相同没有去重效果;
#--------------------------------------------------------------------------------------
-8920692834900147942
-8920692834900147942
------------------------------------------------------------
(<__main__.C object at 0x000001DDE729B940>, <__main__.C object at 0x000001DDE729B978>)
[<__main__.C object at 0x000001DDE729B940>, <__main__.C object at 0x000001DDE729B978>]
{<__main__.C object at 0x000001DDE729B940>, <__main__.C object at 0x000001DDE729B978>}
总结:
- hash 值相同 相当于门牌号相同,两个人住一个房间;,没有去重效果;集合中key相同,才有去重复效果;
- 不同的hash算法hash冲突率不一样;
1.3 操作符重载
方法 | 含义 |
---|---|
_eq_ (True 去重;False不去重) | 对应==操作符,判断2个对象是否相等,返回bool值 |
_hash_ 方法只是返回一个hash值作为set的key,但是 去重 ,还需要 _eq_ 来判断2个对象是否相等。
hash值相等,只是hash冲突,不能说明两个对象是相等的。
因此,一般来说提供 _hash_ 方法是为了作为set或者dict的key,所以 去重 要同时提供_eq_ 方法。
hash 值相同+eq方法 有去重效果;
class A:pass
class B(A):pass
class C(B):
def __hash__(self): # hash门牌号码;
return hash('abc')
def __eq__(self,other):
return True
def __init__(self,name):
self.name = name
print('~~~~~~~~~~~~')
def __repr__(self):
return self.name
c = C('tom')
p = C('peter')
print('-'*60)
print((c,p))
print([c,p])
print({c,p}) # hash值相同也 可以去重+eq方法;
#-------------------------------------------------------------------------------------
~~~~~~~~~~~~
~~~~~~~~~~~~
------------------------------------------------------------
(tom, peter)
[tom, peter]
{tom}
原则上:key相同,才会有去重效果;hash值相同代表在同一个房间;
可不可以hash 验证
有eq在,hash等于None;
eq=false ,可hash;
eq=True,不可hash;
不可hash对象isinstance(p1, collections.Hashable)一定为False
import collections
print(isinstance(c,collections.Hashable))
#--------------------------------------------------------------
True
C:\ProgramData\Miniconda3\lib\site-packages\ipykernel_launcher.py:2: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working