【问题标题】:Add List to Set is Possible in Java but not in Python?在 Java 中可以添加列表到集合,但在 Python 中不行?
【发布时间】:2014-09-10 19:50:30
【问题描述】:

我是 Python 新手,偶然发现将 list 添加到 set。现在我知道reason 为什么这是不可能的,因为list 是可变的,所以它的hashcode(或Python 对应的概念)会改变。回顾我在 Java 中的编程,我发现我已经这样做了很多次。

HashSet<ArrayList<String>> masterCollection = new HashSet<ArrayList<String>>();
ArrayList<String> a = new ArrayList<String>();
masterCollection.add(a);
a.add("Hello, World");
for(ArrayList<String> list : masterCollection) {
    // do something to list
}

我没有注意到上述代码有任何异常行为。我什至使用ArrayList 作为HashMap 的键,并成功完成了我的任务。

所以想问一下Python内部在这方面和Java有什么不同,写上面的代码有没有需要注意的地方。

【问题讨论】:

  • 语言不同。即使使用相同的术语,所有语言的行为方式也不相同。
  • @Kayaman 我知道它们是不同的,我知道这种差异。我想知道 Java 是如何做到这一点的,而 Python 没有。现在 Python 的工作方式似乎更合理:set 不应该一直负责监控其元素的hashcode 并相应地进行更改。但我认为ArrayList 没有一种机制可以在每次其元素更改时报告其hashcode 更改。那么它是如何工作的呢?
  • 这是一个众所周知的事实,如果一个对象在HashSet(或类似的与哈希相关的构造)中更改其哈希码,则结果是未定义的。这就是为什么你应该只在其中放入不可变的东西。
  • @zyl1024 实际上,除非您有一个非常具体(且奇怪)的用例,否则您尝试做的事情是没有意义的:set 的使用强制了列表的唯一性(集合中的任何两个列表都不应该相同)。但是,如果列表不断变化 - 你如何强制执行?现在把同样的问题带到多线程环境中,你就陷入了真正的混乱......

标签: java python arraylist set internals


【解决方案1】:

列表在 python 中是不可散列的,因为它们没有定义__hash__。这是有原因的,但是您可以想象定义自己的可变类,只要所述哈希在对象的整个生命周期内都不会改变。例如,使用id(x) 作为哈希。事实上,您可能已经在自己的许多类中不知不觉地实现了这一点。

我将引用 docs 关于“可哈希”的内容:

所有 Python 的不可变内置对象都是可散列的,而没有 可变容器(例如列表或字典)是。对象 默认情况下,用户定义类的实例是可散列的;他们 所有比较不相等(除了自己),它们的哈希值为 他们的id()

可变性和哈希性是耦合的,但根本不是一回事。

【讨论】:

    【解决方案2】:

    这个post 解释得很清楚。简而言之,Java 和 Python 都使用内部的 hash_table 来实现集合,并使用哈希码作为 key,不同之处在于 Python 要求被哈希的变量是不可变的,而 Java 则不需要,这会导致有线行为:

    【讨论】:

      猜你喜欢
      • 2013-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多