【发布时间】:2017-06-15 22:05:29
【问题描述】:
更新:
- 从 CPython 3.6 开始,字典有一个版本(感谢 pylang 向我展示这个)。
- 如果他们将相同的版本添加到列表中并将其公开,我原始帖子中的所有 3 个断言都会通过!它肯定会满足我的需求。它们的实现与我的设想不同,但我喜欢它。
- 事实上,我觉得我不能使用字典版本:
- 它不公开。 Jake Vanderplas 展示了如何在 post 中公开它,但他警告说:绝对不能将代码用于任何目的,而不仅仅是为了好玩。我同意他的理由。
- 在我的所有用例中,数据在概念上都是元素数组,每个元素都具有相同的结构。元组列表很自然。使用字典会使代码不那么自然,而且可能更麻烦。
- 有人知道是否有计划将版本添加到列表中吗?
- 有计划公开吗?
如果有计划将 version 添加到列表并公开,我会觉得现在提出一个不兼容的 VersionedList 会很尴尬。我只会实现我需要的最低限度并勉强过活。
下面是原帖
事实证明,很多时候我想要一个不可变的列表,VersionedList 几乎可以工作(有时甚至更好)。
- 有人实施了版本化列表吗?
- 是否有更好、更 Pythonic 的概念可以满足我的需求? (请参阅下面的动机。)
我所说的版本化列表是指:
- 行为类似于列表的类
-
对实例或实例中的元素的任何更改都会导致
instance.version()被更新。所以,如果alist是一个普通列表:a = VersionedList(alist) a_version = a.version() change(a) assert a_version != a.version() reverse_last_change(a) -
如果列表是可散列的,hash() 将实现上述目的并满足以下动机中确定的所有需求。我们需要以一种不会有所有与“hash()”相同的问题的方式定义“version()”。
如果两个列表中的相同数据极不可能发生,除非在初始化时,我们将没有理由测试深度相等。来自 (https://docs.python.org/3.5/reference/datamodel.html#object.hash) 唯一需要的属性是比较相等的对象具有相同的哈希值。如果我们不对'version()' 强加这个要求,'version()' 似乎不会有使列表不可散列的所有相同问题。所以不像哈希,相同的内容不意味着相同的版本
#contents of 'a' are now identical to original, but... assert a_version != a.version() b = VersionedList(alist) c = VersionedList(alist) assert b.version() != c.version() -
对于 VersionList,如果任何尝试修改
__get__的结果会自动生成副本而不是修改底层实现数据,那将是很好的。我认为唯一的其他选择是让__get__始终返回元素的副本,这对于我能想到的所有用例来说都是非常低效的。我认为我们需要将元素限制为不可变对象(深度不可变,例如:排除带有列表元素的元组)。我可以想到 3 种方法来实现这一点:- 只允许不能包含可变元素的元素(int、str 等都可以,但不包括元组)。 (这对我的情况来说太局限了)
- 将代码添加到
__init__、__set__等以遍历输入以深入检查可变子元素。 (昂贵,有什么办法可以避免这种情况?) - 还允许更复杂的元素,但要求它们是高度不可变的。也许要求他们公开
deeply_immutable属性。 (这对我所有的用例来说都很容易)
动机:
-
如果我正在分析数据集,我经常需要执行多个返回大型数据集的步骤(注意:由于数据集是有序,因此最好用列表而不是集合来表示)。
如果在几个步骤结束时(例如:5)结果我需要执行不同的分析(例如:回到步骤 4),我想知道步骤 3 中的数据集没有被意外更改.这样我就可以从第 4 步开始,而不是重复第 1-3 步。
-
我有依赖并返回数组值对象(在线性代数意义上)的函数(控制点、一阶导数、二阶导数、偏移量、轮廓等)。基本“数组”是
knots。control-points()取决于:knots,algorithm_enumfirst-derivative()取决于:control-points(),knots
@ 987654340@ 取决于:first-derivative(),control-points(),knots,offset_distanceoutline()取决于:offset(),end_type_enum如果
offset_distance发生变化,我想避免重新计算一阶导数()和控制点()。为避免重新计算,我需要知道没有意外更改结果“数组”。如果“结”发生变化,我需要重新计算所有内容,而不是依赖于之前的结果“数组”。
要实现这一点,
knots和所有“数组值”对象都可以是 VersionedList。
仅供参考:我曾希望利用像 numpy.ndarray 这样的高效类。在我的大多数用例中,元素在逻辑上都有结构。必须在精神上跟踪索引的多维意味着使用 ndarray 实现和调试算法要困难很多倍。事实证明,基于 namedtuples 的 namedtuples 列表的实现更具可持续性。
【问题讨论】:
-
你能澄清最后一段代码吗?它不是有效的 Python。向我们展示您将使用的代码,完全按照您的设想使用。
-
knots[]应该是什么?看起来您正试图将knots声明为一个数组,但 Python 中没有变量声明,您可能的意思是它是一个列表,而不是一个数组...但是您这样做 提到数组,但你到底是什么意思?array.array?numpy.ndarray? -
在实际实现中,所有的数组都是对象的成员。这使得拥有独立实例变得容易。所以,调用有空的参数列表。为了阐明依赖关系,实际代码必须包含大类的大部分。
-
查看对我的评论的编辑,数组是什么意思。
-
我在过去使用
dict完成了此操作,解决方案是使用“已删除”元素来表示已删除的密钥,并将每个新版本中的更新密钥存储为单独的dicts,然后进行深度树展平以获得当前版本。使用列表会更复杂,因为您还需要保持顺序和关系,而不仅仅是在一个级别上 - 这将很快让您意识到您需要构建一个状态机(CPU 密集型)或创建一个新的将每个破坏性更改复制到原始列表(内存密集型)。鉴于这些问题,我怀疑这种结构的实用性。