Python:What the f*ck Python(上) (5)

Output:

>>> type(list(some_dict.keys())[0]) <class 'str'> >>> s = SomeClass('s') >>> some_dict[s] = 40 >>> some_dict # 预期: 两个不同的键值对 {'s': 40} >>> type(list(some_dict.keys())[0]) <class 'str'>

说明:

由于 SomeClass 会从 str 自动继承 __hash__ 方法,所以 s 对象和 "s" 字符串的哈希值是相同的。

而 SomeClass("s") == "s" 为 True 是因为 SomeClass 也继承了 str 类 __eq__ 方法。

由于两者的哈希值相同且相等,所以它们在字典中表示相同的键。

如果想要实现期望的功能, 我们可以重定义 SomeClass 的 __eq__ 方法.

class SomeClass(str): def __eq__(self, other): return ( type(self) is SomeClass and type(other) is SomeClass and super().__eq__(other) ) # 当我们自定义 __eq__ 方法时, Python 不会再自动继承 __hash__ 方法 # 所以我们也需要定义它 __hash__ = str.__hash__ some_dict = {'s':42}

Output:

>>> s = SomeClass('s') >>> some_dict[s] = 40 >>> some_dict {'s': 40, 's': 42} >>> keys = list(some_dict.keys()) >>> type(keys[0]), type(keys[1]) <class 'str'> <class '__main__.SomeClass'> 25. Let's see if you can guess this? >>> a, b = a[b] = {}, 5 >>> a {5: ({...}, 5)}

说明:
根据 ,赋值语句的形式如下:

(target_list "=")+ (expression_list | yield_expression)

赋值语句计算表达式列表(expression list)(请记住,这可以是单个表达式或以逗号分隔的列表, 后者返回元组)并将单个结果对象从左到右分配给目标列表中的每一项。

(target_list "=")+ 中的 + 意味着可以有一个或多个目标列表。在这个例子中,目标列表是 a, b 和 a[b]。表达式列表只能有一个,是 {}, 5。

这话看着非常的晦涩,我们来看一个简单的例子:

a, b = b, c = 1, 2 print(a, b, c)

Output:

1 1 2

在这个简单的例子中,目标列表是 a, b 和 b, c,表达式是 1, 2。将表达式从左到右赋给目标列表,上述例子就可以拆分成:

a, b = 1, 2 b, c = 1, 2

所以结果就是 1 1 2。

那么,原例子就不难理解了,拆解开来就是:

a, b = {}, 5 a[b] = a, b

这里不能写作 a[b] = {}, 5,因为这样第一句中的 {} 和第二句中的 {} 其实就是不同的对象了,而实际他们是同一个对象。这就形成了循环引用,输出中的 {...} 指与 a 引用了相同的对象。
我们来验证一下:

>>> a[b][0] is a True

可见确实是同一个对象。

以下是一个简单的循环引用的例子:

>>> some_list = some_list[0] = [0] >>> some_list [[...]] >>> some_list[0] [[...]] >>> some_list is some_list[0] True >>> some_list[0][0][0][0][0][0] == some_list True

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdgwf.html