Pthon魔术方法(Magic Methods)-hash
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.hash方法
__hash__:
内建函数hash()调用的返回值,返回一个整数。如果定义这个方法该类的实例就可hash。 __eq__:
对应"=="操作符,判断两个对象内容是否相等,返回bool值。
定义了这个方法,如果不提供"__hash__"方法,那么实例将不可hash了。
"__hash__"方法只是返回一个hash值作为set的key,但是去重还需要"__eq__"来判断两个对象是否相等。
hash值相同,只是hash冲突,不能说明两个对象是相等的。因此一半来说提供"__hash__"方法是为了作为set或者dict的key,如果去重同时要提供"__eq__"方法。
温馨提示:
不可hash对象isinstance(p1,collections.Hashable)一定为False。
去重需要提供"__eq__"方法。
二.案例展示
#!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie """
设计二维坐标类Point,使其成为可hash类型,并比较2个坐标的实例是否相等。
""" from collections import Hashable class Point:
def __init__(self,x,y):
self.x = x
self.y = y def __hash__(self):
return hash((self.x,self.y)) def __eq__(self, other):
if self is other:
return True
else:
return self.x == other.x and self.y == other.y def __repr__(self):
return "{}:{}".format(self.x,self.y) p1 = Point(10,20)
p2 = Point(10,20) print(hash(p1))
print(hash(p2)) print(p1 is p2)
print(p1 == p2)
print(hex(id(p1)),hex(id(p2)))
print(set((p1,p2)))
print(isinstance(p1,Hashable)) #以上代码执行结果如下:
3713074054217192181
3713074054217192181
False
True
0x137152b7888 0x137152b9348
{10:20}
True
三.小时牛刀
1>.list类实例为什么不可hash?
class list(object):
"""
Built-in mutable sequence. If no argument is given, the constructor creates a new empty list.
The argument must be an iterable if specified.
"""
def append(self, *args, **kwargs): # real signature unknown
""" Append object to the end of the list. """
pass def clear(self, *args, **kwargs): # real signature unknown
""" Remove all items from list. """
pass def copy(self, *args, **kwargs): # real signature unknown
""" Return a shallow copy of the list. """
pass def count(self, *args, **kwargs): # real signature unknown
""" Return number of occurrences of value. """
pass def extend(self, *args, **kwargs): # real signature unknown
""" Extend list by appending elements from the iterable. """
pass def index(self, *args, **kwargs): # real signature unknown
"""
Return first index of value. Raises ValueError if the value is not present.
"""
pass def insert(self, *args, **kwargs): # real signature unknown
""" Insert object before index. """
pass def pop(self, *args, **kwargs): # real signature unknown
"""
Remove and return item at index (default last). Raises IndexError if list is empty or index is out of range.
"""
pass def remove(self, *args, **kwargs): # real signature unknown
"""
Remove first occurrence of value. Raises ValueError if the value is not present.
"""
pass def reverse(self, *args, **kwargs): # real signature unknown
""" Reverse *IN PLACE*. """
pass def sort(self, *args, **kwargs): # real signature unknown
""" Stable sort *IN PLACE*. """
pass def __add__(self, *args, **kwargs): # real signature unknown
""" Return self+value. """
pass def __contains__(self, *args, **kwargs): # real signature unknown
""" Return key in self. """
pass def __delitem__(self, *args, **kwargs): # real signature unknown
""" Delete self[key]. """
pass def __eq__(self, *args, **kwargs): # real signature unknown
""" Return self==value. """
pass def __getattribute__(self, *args, **kwargs): # real signature unknown
""" Return getattr(self, name). """
pass def __getitem__(self, y): # real signature unknown; restored from __doc__
""" x.__getitem__(y) <==> x[y] """
pass def __ge__(self, *args, **kwargs): # real signature unknown
""" Return self>=value. """
pass def __gt__(self, *args, **kwargs): # real signature unknown
""" Return self>value. """
pass def __iadd__(self, *args, **kwargs): # real signature unknown
""" Implement self+=value. """
pass def __imul__(self, *args, **kwargs): # real signature unknown
""" Implement self*=value. """
pass def __init__(self, seq=()): # known special case of list.__init__
"""
Built-in mutable sequence. If no argument is given, the constructor creates a new empty list.
The argument must be an iterable if specified.
# (copied from class doc)
"""
pass def __iter__(self, *args, **kwargs): # real signature unknown
""" Implement iter(self). """
pass def __len__(self, *args, **kwargs): # real signature unknown
""" Return len(self). """
pass def __le__(self, *args, **kwargs): # real signature unknown
""" Return self<=value. """
pass def __lt__(self, *args, **kwargs): # real signature unknown
""" Return self<value. """
pass def __mul__(self, *args, **kwargs): # real signature unknown
""" Return self*value. """
pass @staticmethod # known case of __new__
def __new__(*args, **kwargs): # real signature unknown
""" Create and return a new object. See help(type) for accurate signature. """
pass def __ne__(self, *args, **kwargs): # real signature unknown
""" Return self!=value. """
pass def __repr__(self, *args, **kwargs): # real signature unknown
""" Return repr(self). """
pass def __reversed__(self, *args, **kwargs): # real signature unknown
""" Return a reverse iterator over the list. """
pass def __rmul__(self, *args, **kwargs): # real signature unknown
""" Return value*self. """
pass def __setitem__(self, *args, **kwargs): # real signature unknown
""" Set self[key] to value. """
pass def __sizeof__(self, *args, **kwargs): # real signature unknown
""" Return the size of the list in memory, in bytes. """
pass __hash__ = None
class list(object):(源码解析)
2>.functools.lru_cache使用到的functools.HashedSeq类继承自list,为什么可hash?
class _HashedSeq(list):
""" This class guarantees that hash() will be called no more than once
per element. This is important because the lru_cache() will hash
the key multiple times on a cache miss. """ __slots__ = 'hashvalue' def __init__(self, tup, hash=hash):
self[:] = tup
self.hashvalue = hash(tup) def __hash__(self):
return self.hashvalue
class _HashedSeq(list):源码解析