Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

字典对象不能使用 set 去重 #7

Open
2018-11-27 opened this issue Aug 5, 2022 · 1 comment
Open

字典对象不能使用 set 去重 #7

2018-11-27 opened this issue Aug 5, 2022 · 1 comment
Assignees
Labels
Processed question Further information is requested

Comments

@2018-11-27
Copy link
Member

这是大的问题,在一些场景中我们必须对字典对象去重,这就得引入或现写非哈希的去重算法,极为不便。如果能直接使用set去重,将大幅提高代码开发效率及可读性。我们能否做到让 gdict 对象使用 set 去重?

@2018-11-27
Copy link
Member Author

2018-11-27 commented Aug 5, 2022

set 能对字典对象去重,将会出现一个更大的问题。首先你必须清楚 set 为什么不能对字典对象去重,因为字典是一个可变的容器,将字典对象加入到 set 中并不影响它可变的特性。设想一种情况,两个不相等的字典对象加入到了 set 中,之后这两个字典对象经过变化值相等了,那这问题就大了,set 中的值不唯一了,这颠覆 set 的理念。

说了这么多是为了先给你建立一个正确的认知。然后呢我们就喜欢干这种颠覆认知的事情,我们完全可以做到让 gdict 对象使用 set 去重。

你必须了解下面两件事:

  • 哈希理念:两个约相等的对象的哈希值一定相等,反之未必。
  • set 去重流程:先调用对象的 __hash__ 方法,若返回值相等,再调用 __eq__ 方法...

结合哈希理念与 set 去重流程,我们从 __hash__ 方法入手:

def __hash__(self):
    return -2

重写 __hash__ 方法并固定返回值,这意味着 gdict 对象是可哈希的了,并且哈希值始终相等。此时 gdict 对象已经可以使用 set 去重了,它将忽略哈希检查,始终检查值是否相等。

>>> a1 = gdict(a='A1')
>>> a2 = gdict(a='A2')
>>> xx = gdict(a='A1')
>>> {a1, a2, xx}
{{'a': 'A1'}, {'a': 'A2'}}

开头我们提到过这样做会出现一个更大的问题,会使 set 中的值不唯一,如下代码展示:

>>> a1 = gdict(a='A1')
>>> a2 = gdict(a='A2')
>>> x = {a1, a2}
>>> a2.a = 'A1'
>>> x
{{'a': 'A1'}, {'a': 'A1'}}

因此,gdict 对象可以使用 set 去重,但要格外小心。

@2018-11-27 2018-11-27 pinned this issue Aug 5, 2022
@2018-11-27 2018-11-27 self-assigned this Aug 5, 2022
@2018-11-27 2018-11-27 added question Further information is requested Processed labels Aug 5, 2022
@2018-11-27 2018-11-27 unpinned this issue May 2, 2023
@2018-11-27 2018-11-27 changed the title 字典对象不能使用set去重 字典对象不能使用 set 去重 May 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Processed question Further information is requested
Projects
None yet
Development

No branches or pull requests

1 participant