可哈希

 实践

1、

 

2、

def f1():
s='s1'
print(s.__hash__())
def f2():
f1()
s='s1'
print(s.__hash__())
f2()

def g1():
s='s2'
print(s.__hash__())
del s
def g2():
g1()
s='s2'
print(s.__hash__())
g2()

def h1():
print('s3'.__hash__())
def h2():
h1()
print('s3'.__hash__())
h2()
 
每组一致。
 

 

https://docs.python.org/zh-cn/dev/glossary.html#term-hashable

hash-based pyc -- 基于哈希的 pyc

使用对应源文件的哈希值而非最后修改时间来确定其有效性的字节码缓存文件。 参见 已缓存字节码的失效

hashable -- 可哈希

一个对象的哈希值如果在其生命周期内绝不改变,就被称为 可哈希 (它需要具有 __hash__() 方法),并可以同其他对象进行比较(它需要具有 __eq__() 方法)。可哈希对象必须具有相同的哈希值比较结果才会相同。

可哈希性使得对象能够作为字典键或集合成员使用,因为这些数据结构要在内部使用哈希值。

大多数 Python 中的不可变内置对象都是可哈希的;可变容器(例如列表或字典)都不可哈希;不可变容器(例如元组和 frozenset)仅当它们的元素均为可哈希时才是可哈希的。 用户定义类的实例对象默认是可哈希的。 它们在比较时一定不相同(除非是与自己比较),它们的哈希值的生成是基于它们的 id()

 

hash-based pyc

A bytecode cache file that uses the hash rather than the last-modified time of the corresponding source file to determine its validity. See Cached bytecode invalidation.

hashable

An object is hashable if it has a hash value which never changes during its lifetime (it needs a __hash__() method), and can be compared to other objects (it needs an __eq__() method). Hashable objects which compare equal must have the same hash value.

Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally.

Most of Python’s immutable built-in objects are hashable; mutable containers (such as lists or dictionaries) are not; immutable containers (such as tuples and frozensets) are only hashable if their elements are hashable. Objects which are instances of user-defined classes are hashable by default. They all compare unequal (except with themselves), and their hash value is derived from their id().

 

builtins.py

def hash(*args, **kwargs): # real signature unknown
"""
Return the hash value for the given object.

Two objects that compare equal must also have the same hash value, but the
reverse is not necessarily true.
"""
pass
 
对象相等则哈希值相等,反之不一定成立。
 
https://docs.python.org/zh-cn/dev/library/functions.html#hash
hash(object)

返回该对象的哈希值(如果它有的话)。哈希值是整数。它们在字典查找元素时用来快速比较字典的键。相同大小的数字变量有相同的哈希值(即使它们类型不同,如 1 和 1.0)。

备注

 

For objects with custom __hash__() methods, note that hash() truncates the return value based on the bit width of the host machine. See __hash__ for details.

 
 
object.__hash__(self)

通过内置函数 hash() 调用以对哈希集的成员进行操作,属于哈希集的类型包括 setfrozenset 以及 dict__hash__() 应该返回一个整数。对象比较结果相同所需的唯一特征属性是其具有相同的哈希值;建议的做法是把参与比较的对象全部组件的哈希值混在一起,即将它们打包为一个元组并对该元组做哈希运算。例如:

def __hash__(self):
    return hash((self.name, self.nick, self.color))

备注

 3. 数据模型 — Python 3.13.0a0 文档 https://docs.python.org/zh-cn/dev/reference/datamodel.html#object.__hash__

hash() 会从一个对象自定义的 __hash__() 方法返回值中截断为 Py_ssize_t 的大小。通常对 64 位构建为 8 字节,对 32 位构建为 4 字节。如果一个对象的 __hash__() 必须在不同位大小的构建上进行互操作,请确保检查全部所支持构建的宽度。做到这一点的简单方法是使用 python -c "import sys; print(sys.hash_info.width)"

If a class does not define an __eq__() method it should not define a __hash__() operation either; if it defines __eq__() but not __hash__(), its instances will not be usable as items in hashable collections. If a class defines mutable objects and implements an __eq__() method, it should not implement __hash__(), since the implementation of hashable collections requires that a key's hash value is immutable (if the object's hash value changes, it will be in the wrong hash bucket).

用户定义的类默认带有 __eq__() 和 __hash__() 方法;使用它们与任何对象(自己除外)比较必定不相等,并且 x.__hash__() 会返回一个恰当的值以确保 == y 同时意味着 is y 且 hash(x) == hash(y)

一个类如果重载了 __eq__() 且没有定义 __hash__() 则会将其 __hash__() 隐式地设为 None。当一个类的 __hash__() 方法为 None 时,该类的实例将在一个程序尝试获取其哈希值时正确地引发 TypeError,并会在检测 isinstance(obj, collections.abc.Hashable) 时被正确地识别为不可哈希对象。

如果一个重载了 __eq__() 的类需要保留来自父类的 __hash__() 实现,则必须通过设置 __hash__ <ParentClass>.__hash__ 来显式地告知解释器。

如果一个没有重载 __eq__() 的类需要去掉哈希支持,则应该在类定义中包含 __hash__ None。一个自定义了 __hash__() 以显式地引发 TypeError 的类会被 isinstance(obj, collections.abc.Hashable) 调用错误地识别为可哈希对象。

备注

 

在默认情况下,str 和 bytes 对象的 __hash__() 值会使用一个不可预知的随机值“加盐”。 虽然它们在一个单独 Python 进程中会保持不变,但它们的值在重复运行的 Python 间是不可预测的。

This is intended to provide protection against a denial-of-service caused by carefully chosen inputs that exploit the worst case performance of a dict insertion, O(n2) complexity. See http://ocert.org/advisories/ocert-2011-003.html for details.

改变哈希值会影响集合的迭代次序。Python 也从不保证这个次序不会被改变(通常它在 32 位和 64 位构建上是不一致的)。

另见 PYTHONHASHSEED.

在 3.3 版本发生变更: 默认启用哈希随机化。

 
 

id(object)

Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

CPython implementation detail: This is the address of the object in memory.

Raises an auditing event builtins.id with argument id.

 

id(object)

返回对象的“标识值”。该值是一个整数,在此对象的生命周期中保证是唯一且恒定的。两个生命期不重叠的对象可能具有相同的 id() 值。

CPython 实现细节: This is the address of the object in memory.

引发一个 审计事件 builtins.id,附带参数 id

 

 

 

3. 数据模型

3.1. 对象、值与类型

对象 是 Python 中对数据的抽象。 Python 程序中的所有数据都是由对象或对象间关系来表示的。 (从某种意义上说,按照冯·诺依曼的“存储程序计算机”模型,代码本身也是由对象来表示的。)

每个对象都有各自的标识号、类型和值。一个对象被创建后,它的 标识号 就绝不会改变;你可以将其理解为该对象在内存中的地址。 'is' 运算符可以比较两个对象的标识号是否相同;id() 函数能返回一个代表其标识号的整数。

CPython 实现细节: 在 CPython 中,id(x) 就是存放 x 的内存的地址。

对象的类型决定该对象所支持的操作 (例如 "对象是否有长度属性?") 并且定义了该类型的对象可能的取值。type() 函数能返回一个对象的类型 (类型本身也是对象)。与编号一样,一个对象的 类型 也是不可改变的。[1]

有些对象的  可以改变。值可以改变的对象被称为 可变对象;值不可以改变的对象就被称为 不可变对象。(一个不可变容器对象如果包含对可变对象的引用,当后者的值改变时,前者的值也会改变;但是该容器仍属于不可变对象,因为它所包含的对象集是不会改变的。因此,不可变并不严格等同于值不能改变,实际含义要更微妙。) 一个对象的可变性是由其类型决定的;例如,数字、字符串和元组是不可变的,而字典和列表是可变的。

对象绝不会被显式地销毁;然而,当无法访问时它们可能会被作为垃圾回收。允许具体的实现推迟垃圾回收或完全省略此机制 --- 如何实现垃圾回收是实现的质量问题,只要可访问的对象不会被回收即可。

CPython 实现细节: CPython 目前使用带有 (可选) 延迟检测循环链接垃圾的引用计数方案,会在对象不可访问时立即回收其中的大部分,但不保证回收包含循环引用的垃圾。请查看 gc 模块的文档了解如何控制循环垃圾的收集相关信息。其他实现会有不同的行为方式,CPython 现有方式也可能改变。不要依赖不可访问对象的立即终结机制 (所以你应当总是显式地关闭文件)。

注意:使用实现的跟踪或调试功能可能令正常情况下会被回收的对象继续存活。还要注意通过 'try...except' 语句捕捉异常也可能令对象保持存活。

有些对象包含对 "外部" 资源的引用,例如打开文件或窗口。当对象被作为垃圾回收时这些资源也应该会被释放,但由于垃圾回收并不确保发生,这些对象还提供了明确地释放外部资源的操作,通常为一个 close() 方法。强烈推荐在程序中显式关闭此类对象。'try...finally' 语句和 'with' 语句提供了进行此种操作的更便捷方式。

有些对象包含对其他对象的引用;它们被称为 容器。容器的例子有元组、列表和字典等。这些引用是容器对象值的组成部分。在多数情况下,当谈论一个容器的值时,我们是指所包含对象的值而不是其编号;但是,当我们谈论一个容器的可变性时,则仅指其直接包含的对象的编号。因此,如果一个不可变容器 (例如元组) 包含对一个可变对象的引用,则当该可变对象被改变时容器的值也会改变。

类型会影响对象行为的几乎所有方面。甚至对象编号的重要性也在某种程度上受到影响: 对于不可变类型,会得出新值的运算实际上会返回对相同类型和取值的任一现有对象的引用,而对于可变类型来说这是不允许的。例如在 1; 1 之后,a 和 b 可能会也可能不会指向同一个值为一的对象,这取决于具体实现,但是在 []; [] 之后,c 和 d 保证会指向两个不同、单独的新建空列表。(请注意 [] 则是将同一个对象赋值给 c 和 d。)

 

 

字节串

字节串对象是不可变的数组。其中每个条目都是一个 8 位字节,以取值范围 0 <= x < 256 的整型数表示。字节串字面值 (例如 b'abc') 和内置的 bytes() 构造器可被用来创建字节串对象。字节串对象还可以通过 decode() 方法解码为字符串。

 

字符与整数

字符串

A string is a sequence of values that represent Unicode code points. All the code points in the range U+0000 U+10FFFF can be represented in a string. Python doesn't have a char type; instead, every code point in the string is represented as a string object with length 1. The built-in function ord() converts a code point from its string form to an integer in the range 10FFFFchr() converts an integer in the range 10FFFF to the corresponding length 1 string object. str.encode() can be used to convert a str to bytes using the given text encoding, and bytes.decode() can be used to achieve the opposite.

 

 

 


None 对象
None 单例 singleton
 
None 对象 — Python 3.13.0a0 文档 https://docs.python.org/zh-cn/dev/c-api/none.html

None 对象

Note that the PyTypeObject for None is not directly exposed in the Python/C API. Since None is a singleton, testing for object identity (using == in C) is sufficient. There is no PyNone_Check() function for the same reason.

PyObject *Py_None

The Python None object, denoting lack of value. This object has no methods and is immortal.

在 3.12 版本发生变更: Py_None is immortal.

Py_RETURN_NONE

Return Py_None from a function.

 
 
https://docs.python.org/zh-cn/dev/c-api/long.html

整数型对象

所有整数都实现为长度任意的长整数对象。

 
 
 
posted @ 2023-07-31 12:25  papering  阅读(53)  评论(0编辑  收藏  举报