为什么以及如何使用Python函数?

Mad*_*ist 49 python hash

我最近在Python中尝试了以下命令:

>>> {lambda x: 1: 'a'}
{<function __main__.<lambda>>: 'a'}

>>> def p(x): return 1
>>> {p: 'a'}
{<function __main__.p>: 'a'}
Run Code Online (Sandbox Code Playgroud)

两个dict创作的成功表明lambda和常规函数都是可清除的.(像{[]: 'a'}失败的东西TypeError: unhashable type: 'list').

哈希显然不一定是函数的ID:

>>> m = lambda x: 1
>>> id(m)
140643045241584
>>> hash(m)
8790190327599
>>> m.__hash__()
8790190327599
Run Code Online (Sandbox Code Playgroud)

最后一个命令显示该__hash__方法是为lambdas 显式定义的,即,这不是Python根据类型计算的一些自动化的东西.

使功能可以清洗的动机是什么?对于奖金,函数的哈希是什么?

use*_*ica 44

没什么特别的.如您所见,检查__hash__函数类型的未绑定方法:

>>> def f(): pass
...
>>> type(f).__hash__
<slot wrapper '__hash__' of 'object' objects>
Run Code Online (Sandbox Code Playgroud)

of 'object' objects部分是指它只是继承了默认的基于身份__hash__object.身份的功能==hash工作.对于任何继承的类型,id和之间的区别hash是正常的object.__hash__:

>>> x = object()
>>> id(x)
40145072L
>>> hash(x)
2509067
Run Code Online (Sandbox Code Playgroud)

您可能认为__hash__只应该为不可变对象定义,并且您几乎是正确的,但是缺少关键细节.__hash__只应为比较中涉及的所有内容==都是不可变的对象定义.对于==基于身份的对象,基于身份也是完全标准的hash,因为即使对象是可变的,它们也不可能以改变其身份的方式变得可变.具有基于身份的文件,模块和其他可变对象==都以这种方式运行.

  • @Delioth:`==`对于没有指定其他行为的任何类型的标识. (4认同)
  • @wallyk:我已经添加了一些关于原因的详细说明. (3认同)

Tim*_*ers 22

例如,创建函数对象集或通过函数索引字典可能是有用的.不可变对象通常支持__hash__.在任何情况下,由a def或a 定义的函数之间没有内部差异lambda- 这纯粹是语法.

使用的算法取决于Python的版本.看起来你在64位盒子上使用最新版本的Python.在这种情况下,函数对象的散列是其右移id()4位,结果被视为带符号的64位整数.完成右移是因为对象地址(id()结果)通常是对齐的,因此它们的最后3或4位始终为0,这对于散列函数来说是一个温和的烦人属性.

在您的具体示例中,

>>> i = 140643045241584 # your id() result
>>> (i >> 4) | ((i << 60) & 0xffffffffffffffff) # rotate right 4 bits
8790190327599  # == your hash() result
Run Code Online (Sandbox Code Playgroud)

  • @JulienBernu,请参阅@ user2357112的回复 - 就`==`而言,它是不可变的,这都是`__hash __()`关心的. (2认同)