我在理解如何管理numpy对象散列性时遇到了一些问题。
>>> import numpy as np
>>> class Vector(np.ndarray):
... pass
>>> nparray = np.array([0.])
>>> vector = Vector(shape=(1,), buffer=nparray)
>>> ndarray = np.ndarray(shape=(1,), buffer=nparray)
>>> nparray
array([ 0.])
>>> ndarray
array([ 0.])
>>> vector
Vector([ 0.])
>>> '__hash__' in dir(nparray)
True
>>> '__hash__' in dir(ndarray)
True
>>> '__hash__' in dir(vector)
True
>>> hash(nparray)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'numpy.ndarray'
>>> hash(ndarray)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'numpy.ndarray'
>>> hash(vector)
-9223372036586049780
>>> nparray.__hash__()
269709177
>>> ndarray.__hash__()
269702147
>>> vector.__hash__()
-9223372036586049780
>>> id(nparray)
4315346832
>>> id(ndarray)
4315234352
>>> id(vector)
4299616456
>>> nparray.__hash__() == id(nparray)
False
>>> ndarray.__hash__() == id(ndarray)
False
>>> vector.__hash__() == id(vector)
False
>>> hash(vector) == vector.__hash__()
True
为什么
__hash__
方法,但是不可散列numpy.ndarray
的类定义了__hash__
,是可散列的吗?我遗漏了什么吗?
我使用的是Python2.7.1和Numpy1.6.1
谢谢你的帮助!
编辑:添加对象id
s
编辑2:
在deinonychusaur评论之后,我试着找出散列是否基于内容,我玩了numpy.nparray.dtype
,发现了一些很奇怪的东西:
>>> [Vector(shape=(1,), buffer=np.array([1], dtype=mytype), dtype=mytype) for mytype in ('float', 'int', 'float128')]
[Vector([ 1.]), Vector([1]), Vector([ 1.0], dtype=float128)]
>>> [id(Vector(shape=(1,), buffer=np.array([1], dtype=mytype), dtype=mytype)) for mytype in ('float', 'int', 'float128')]
[4317742576, 4317742576, 4317742576]
>>> [hash(Vector(shape=(1,), buffer=np.array([1], dtype=mytype), dtype=mytype)) for mytype in ('float', 'int', 'float128')]
[269858911, 269858911, 269858911]
我很困惑。。。numpy中是否有某种(类型独立)缓存机制?
我在Python 2.6.6和numpy 1.3.0中得到了相同的结果。根据the Python glossary,如果定义了
__hash__
(而不是None
),并且定义了__eq__
或__cmp__
,那么对象应该是散列的。ndarray.__eq__
和ndarray.__hash__
都被定义并返回有意义的内容,所以我不明白hash
为什么会失败。在快速的google之后,我找到了this post on the python.scientific.devel mailing list,它声明数组从来没有打算是散列的-所以为什么定义ndarray.__hash__
,我不知道。注意isinstance(nparray, collections.Hashable)
返回True
。编辑:注意
nparray.__hash__()
返回的结果与id(nparray)
相同,因此这只是默认实现。也许在早期版本的python中删除__hash__
的实现是困难的或不可能的(2.6中显然引入了__hash__ = None
技术),所以他们使用某种C-API魔法来实现这一点,这种方法不会传播到子类,也不会阻止您显式调用ndarray.__hash__
?Python 3.2.2和当前的numpy 2.0.0与repo有所不同。
__cmp__
方法不再存在,因此哈希性现在需要__hash__
和__eq__
(请参见Python 3 glossary)。在这个版本的numpy中,ndarray.__hash__
是被定义的,但是它只是None
,所以不能被调用。hash(nparray)
失败,isinstance(nparray, collections.Hashable)
按预期返回False
。hash(vector)
也失败了。这不是一个明确的答案,但这里有一些轨道来理解这种行为。
我这里指的是1.6.1版本的numpy代码。
根据
numpy.ndarray
对象实现(看,numpy/core/src/multiarray/arrayobject.c
),将hash
方法设置为NULL
。此
tp_hash
属性似乎在numpy/core/src/multiarray/multiarraymodule.c
中被重写。请参见DUAL_INHERIT
、DUAL_INHERIT2
和initmultiarray
函数,其中tp_hash
属性被修改。例如: pyarraydesrc_Type.tp_hash=PyArray_DescrHash
根据
hashdescr.c
,hash实现如下:相关问题 更多 >
编程相关推荐