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)}说明:
根据 ,赋值语句的形式如下:
赋值语句计算表达式列表(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 引用了相同的对象。
我们来验证一下:
可见确实是同一个对象。
以下是一个简单的循环引用的例子:
>>> 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