gpt4 book ai didi

python - Python-版本列表而不是不可变列表?

转载 作者:行者123 更新时间:2023-11-28 18:22:06 25 4
gpt4 key购买 nike

更新:
从CPython 3.6开始,字典就有了一个版本(感谢pylang向我展示这个版本)。
如果他们把同一个版本添加到列表中并公开,那么我的原始帖子中的3个断言都将通过!它一定能满足我的需要。它们的实现与我预想的不同,但我喜欢它。
事实上,我觉得我不能使用字典版本:
不公开。Jake Vanderplas展示了如何在post中公开它,但他警告说:除了简单的娱乐之外,绝对不能将代码用于任何目的。我同意他的理由。
在我的所有用例中,数据都是概念上的元素数组,每个元素都具有相同的结构。元组列表是一个自然的匹配。使用字典会使代码不那么自然,而且可能更麻烦。
有人知道是否有计划将版本添加到列表中吗?
有计划公开吗?
如果有计划将版本添加到列表中并将其公开,那么现在提出一个不兼容的版本列表会让我感到尴尬。我只会实现我所需要的最低限度,然后过日子。
原帖子如下
结果发现,很多时候我想要一个不可变的列表,一个VersionedList几乎可以工作得很好(有时甚至更好)。
有人实现了版本列表吗?
有没有更好的,更像蟒蛇的,能满足我需要的概念?(见下面的动机。)
我所说的版本列表是指:
行为类似于列表的类
对实例或实例中的元素所做的任何更改都会导致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()'可能不会出现所有使列表不可更改的问题。所以和hash不同的是,相同的内容并不意味着相同的版本
#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__总是返回元素的副本,这对于我能想到的所有用例来说都是非常低效的我认为我们需要将元素限制为不可变的对象(例如:排除具有列表元素的元组)。我可以想出三种方法来实现这一点:
只允许不能包含可变元素的元素(int、str等可以,但排除元组)。(这对我的案子来说限制太大了)
__init____set__等添加代码,以遍历输入,深入检查可变子元素。(很贵,有没有办法避免这种情况?)
也允许更复杂的元素,但要求它们是深不可变的。可能需要它们公开 deeply_immutable属性。(这对我所有的用例来说都很简单)
动机:
如果我在分析一个数据集,我通常需要执行多个步骤来返回大型数据集(注意:由于数据集是有序的,所以最好用列表而不是集合来表示)。
如果在几个步骤(例如:5)结束时,我需要执行不同的分析(例如:回到步骤4),我想知道步骤3中的数据集并没有被意外更改。这样我就可以从步骤4开始,而不是重复步骤1-3。
我有函数(控制点、一阶导数、二阶导数、偏移量、轮廓等)依赖并返回数组值对象(在线性代数意义上)。基本“数组”是 knots
control-points()取决于: knotsalgorithm_enum
first-derivative()取决于: control-points()knots
offset()取决于: first-derivative()control-points()knotsoffset_distance
outline()取决于: offset()end_type_enum
如果 offset_distance发生更改,我希望避免重新计算一阶导数()和控制点()。为了避免重新计算,我需要知道没有什么意外地改变了结果“数组”。
如果“knots”发生变化,我需要重新计算所有内容,而不依赖于以前的结果“arrays”。
为此, knots和所有“数组值”对象都可以是VersionedList。
仅供参考:我曾希望利用像numpy.ndarray这样的高效课堂。在我的大多数用例中,元素在逻辑上具有结构。要在精神上跟踪索引的多维性意味着使用ndarray实现和调试算法要困难很多倍。一个基于namedtuples的namedtuples列表的实现被证明是更可持续的。

最佳答案

3.6中的私人听写
在Python3.6中,字典现在是私有的(PEP 509)和压缩的(issue 27350),它们分别跟踪版本和保持顺序。这些特性目前在使用CPython 3.6实现时是正确的。尽管面临挑战,Jake VanderPlas在他的blog post中演示了在普通Python中从CPython公开这个版本控制特性的详细演示。我们可以利用他的方法:
确定何时更新词典
维护秩序
例子

import numpy as np

d = {"a": np.array([1,2,3]),
"c": np.array([1,2,3]),
"b": np.array([8,9,10]),
}

for i in range(3):
print(d.get_version()) # monkey-patch
# 524938
# 524938
# 524938

请注意,在更新字典之前,版本号不会更改,如下所示:
d.update({"c": np.array([10, 11, 12])})
d.get_version()
# 534448

此外,还保留了插入顺序(以下内容在Python3.5和3.6的重新启动会话中进行了测试):
list(d.keys())
# ['a', 'c', 'b']

您可以利用这个新的字典行为,避免实现新的数据类型。
细节
对于那些感兴趣的人来说,后者是一种针对任何字典的猴子修补方法,使用以下来自Jake VanderPlas博客文章的修改代码在Python 3.6中实现。此代码在调用 get_version()
import types
import ctypes
import sys
assert (3, 6) <= sys.version_info < (3, 7) # valid only in Python 3.6

py_ssize_t = ctypes.c_ssize_t

# Emulate the PyObjectStruct from CPython
class PyObjectStruct(ctypes.Structure):
_fields_ = [('ob_refcnt', py_ssize_t),
('ob_type', ctypes.c_void_p)]


# Create a DictStruct class to wrap existing dictionaries
class DictStruct(PyObjectStruct):
_fields_ = [("ma_used", py_ssize_t),
("ma_version_tag", ctypes.c_uint64),
("ma_keys", ctypes.c_void_p),
("ma_values", ctypes.c_void_p),
]

def __repr__(self):
return (f"DictStruct(size={self.ma_used}, "
f"refcount={self.ob_refcnt}, "
f"version={self.ma_version_tag})")

@classmethod
def wrap(cls, obj):
assert isinstance(obj, dict)
return cls.from_address(id(obj))

assert object.__basicsize__ == ctypes.sizeof(PyObjectStruct)
assert dict.__basicsize__ == ctypes.sizeof(DictStruct)


# Code for monkey-patching existing dictionaries
class MappingProxyStruct(PyObjectStruct):
_fields_ = [("mapping", ctypes.POINTER(DictStruct))]

@classmethod
def wrap(cls, D):
assert isinstance(D, types.MappingProxyType)
return cls.from_address(id(D))

assert types.MappingProxyType.__basicsize__ == ctypes.sizeof(MappingProxyStruct)


def mappingproxy_setitem(obj, key, val):
"""Set an item in a read-only mapping proxy"""
proxy = MappingProxyStruct.wrap(obj)
ctypes.pythonapi.PyDict_SetItem(proxy.mapping,
ctypes.py_object(key),
ctypes.py_object(val))

mappingproxy_setitem(dict.__dict__,
'get_version',
lambda self: DictStruct.wrap(self).ma_version_tag)

关于python - Python-版本列表而不是不可变列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44532712/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com