跳转到主要内容

不可变类型

项目描述

shoobx.immutable – 不可变类型

https://travis-ci.org/Shoobx/shoobx.immutable.png?branch=master https://coveralls.io/repos/github/Shoobx/shoobx.immutable/badge.svg?branch=master https://img.shields.io/pypi/v/shoobx.immutable.svg https://img.shields.io/pypi/pyversions/shoobx.immutable.svg Documentation Status

此库提供基于状态的不可变类型实现,包括列表、集合和字典。它处理任意深度的嵌套对象结构。

此外,还提供了对修订版不可变类型的支持,允许对不可变类型进行完整的修订历史记录。还提供了一个修订版不可变管理器的示例实现。

可选:提供基于pjpersist的存储机制,用于修订版不可变类型,允许轻松存储版本化不可变类型。

使用不可变类型

不可变对象可以使某些复杂的系统更加合理,因为它们严格控制对象的修改时机和方式。它还保证对象永远不会在子系统中的另一个访问器处更改。

简介

让我们从一个简单的字典开始

>>> import shoobx.immutable as im
>>> with im.create(im.ImmutableDict) as factory:
...     answer = factory({
...         'question': 'Answer to the ultimate question of life, ...',
...         'answer': 0
...     })
>>> answer['answer']
0

但无法再更改任何值

>>> answer['answer'] = 42
Traceback (most recent call last):
...
AttributeError: Cannot update locked immutable object.

不可变对象通过特殊的上下文管理器进行更新,该管理器创建一个可以在上下文管理器块内修改的新版本的对象。

>>> orig = answer
>>> with im.update(answer) as answer:
...     answer['answer'] = 42
>>> answer['answer']
42

请注意,answer 字典是一个全新的对象,而原始对象仍然未修改。

>>> orig is not answer
True
>>> orig['answer']
0

当然,我们也可以创建复杂对象结构,例如通过添加一个列表

>>> with im.update(answer) as answer:
...     answer['witnesses'] = ['Arthur', 'Gag']
>>> answer['witnesses']
['Arthur', 'Gag']

当然,列表已经被转换为它的不可变等效,因此项不能被修改。

>>> isinstance(answer['witnesses'], im.ImmutableList)
True
>>> answer['witnesses'].append('Deep Thought')
Traceback (most recent call last):
...
AttributeError: Cannot update locked immutable object.

但是,不允许从子/子对象更新,因为创建子对象的新版本会从语义上修改其父对象,从而违反不可变性约束。

>>> with im.update(answer['witnesses']) as witnesses:
...     pass
Traceback (most recent call last):
...
AttributeError: update() is only available for master immutables.

系统通过将“主”和“从”模式分配给不可变对象来实现这一点。根不可变对象是主对象,而任何下方的子对象都是从对象。

还支持不可变集合作为核心不可变对象

>>> data = im.ImmutableSet({6})
>>> data
{6}
>>> with im.update(data) as data:
...     data.discard(6)
...     data.add(9)
>>> data
{9}

自定义不可变对象

创建自己的不可变对象非常简单

>>> class Answer(im.Immutable):
...     def __init__(self, question=None, answer=None, witnesses=None):
...         self.question = question
...         self.answer = answer
...         self.witnesses = witnesses
>>> answer = Answer('The Answer', 42, ['Arthur', 'Gag'])
>>> answer.answer
42

注意列表是如何自动转换为它的不可变等效的

>>> isinstance(answer.witnesses, im.ImmutableList)
True

当然,除了更新上下文之外,您不能修改不可变对象

>>> answer.answer = 54
Traceback (most recent call last):
...
AttributeError: Cannot update locked immutable object.
>>> with im.update(answer) as answer:
...     answer.answer = 54
>>> answer.answer
54

修订版不可变对象

由于可变对象为每次更改创建一个新的对象,因此它们非常适合创建需要跟踪整个历史的系统。此软件包通过定义修订管理器API和在其中管理的修订版不可变对象来为此类系统提供支持。

让我们首先创建一个自定义修订版不可变对象

>>> class Answer(im.RevisionedImmutable):
...
...     def __init__(self, question=None, answer=None):
...         self.question = question
...         self.answer = answer

提供了一个修订管理器API的简单实现,以演示可能的实现路径。

>>> data = im.RevisionedMapping()
>>> data['a'] = answer = Answer('Answer to the ultimate question')

答案是目前修订版,并已被添加到管理器中。

>>> data['a'] is answer
True

除了通常的不可变性功能外,修订版不可变对象还具有几个其他属性,有助于管理修订版。

>>> answer.__im_start_on__
datetime.datetime(...)
>>> answer.__im_end_on__ is None
True
>>> answer.__im_manager__
<shoobx.immutable.revisioned.SimpleRevisionedImmutableManager ...>
>>> answer.__im_creator__ is None
True
>>> answer.__im_comment__ is None
True

更新API已扩展以支持设置更改的创建者和注释

>>> answer_r1 = answer
>>> with im.update(answer, 'universe', 'Provide Answer') as answer:
...     answer.answer = 42

现在我们有一个第二版本的答案,设置了注释和创建者

>>> answer.answer
42
>>> answer.__im_start_on__
datetime.datetime(...)
>>> answer.__im_end_on__ is None
True
>>> answer.__im_creator__
'universe'
>>> answer.__im_comment__
'Provide Answer'

第一版现在已退役,并有一个结束日期/时间(等于新修订版的开始日期/时间)

>>> answer_r1.__im_start_on__
datetime.datetime(...)
>>> answer_r1.__im_end_on__ == answer.__im_start_on__
True
>>> answer_r1.__im_state__ == im.interfaces.IM_STATE_RETIRED
True

管理器提供了管理各种修订版的API。

>>> revisions = data.getRevisionManager('a')
>>> len(revisions.getRevisionHistory())
2
>>> revisions.getCurrentRevision(answer_r1) is answer
True

我们可以回滚到以前的版本

>>> revisions.rollbackToRevision(answer_r1)
>>> len(revisions.getRevisionHistory())
1
>>> answer_r1.__im_end_on__ is None
True
>>> answer_r1.__im_state__ == im.interfaces.IM_STATE_LOCKED
True

可选 pjpersist 支持

shoobx.immutable.pjpersist 中提供了一个更严肃且适用于生产的修订管理器API实现,它利用 pjpersist 来存储所有数据。

注意

关于系统内部工作原理的技术讨论位于相应接口的文档字符串中。此外,测试覆盖了许多在此未讨论的特殊情况。

变更

2.0.3 (2021-05-06)

  • 确保在 __im_update__ 中不能再次更新过时的对象。

2.0.2 (2020-04-27)

  • 添加了 enum.Enum 作为不可变类型/常量。这允许将 Enum 分配给 ImmutableBase 属性。

2.0.1 (2020-04-23)

  • 允许 defaultInfo() 装饰器嵌套。

2.0.0 (2020-04-21)

  • 重要:将不可变状态作为列添加到表中。这将需要迁移数据库模式和数据。

  • 引入了新的 IM_STATE_DELETED 状态,该状态标记对象为已删除。

  • 添加了新的 _pj_with_deleted_items 标志,当设置为真时,将容器 API 更改为返回删除的项。

  • 添加了 ImmutableContainer.withDeletedItems() 方法,该方法将克隆容器并设置 _pj_with_deleted_items 标志。这将默认重置所有缓存以禁止不一致的结果。

  • test_functional_deletionAndRevival() 展示了删除和恢复功能。

1.5.0 (2020-04-20)

  • 通过简单地标记对象的最后一个版本为已退休并分配一个结束日期,在 pjpersist ImmutableContainer 中尊重 _pj_remove_documents 标志。这样就可以撤销删除。此外,审计日志现在可以更完整。

  • 允许全局指定创建者和注释,这样 API 就不需要通过所有层传递这些信息。

1.4.3 (2020-02-22)

  • 确保 ImmutableContainer 不接受瞬态对象。这特别重要,因为对象可以在不使用 create() 上下文管理器的情况下以瞬态状态初始化。它还保护对象在更新完成之前不被更新到容器中。

  • 重构了 __delitem__ 测试,使其更简洁,并更清楚地记录用例。

1.4.2 (2020-02-15)

  • 1.4.1 是一个棕色纸袋版本。

1.4.1 (2020-02-15)

  • 遗漏了重新导出 shoobx.immutable.immutable.create

1.4.0 (2020-02-14)

  • 将创建不可变对象的模式改为上下文管理器。注意,仅创建一个如 Immutable() 的对象将给出瞬态对象。首选的模式是

    >>> import shoobx.immutable as im
    >>> with im.create(im.Immutable) as factory:
    ...     imObj = factory()
    

    这使得设置初始属性变得非常简单。有关详细信息,请参阅 README.rst 和文档以及测试。

1.3.1 (2020-02-10)

  • 修复了 ImmutableContainer 中剩余的 _pj_get_resolve_filter 发生。

1.3.0 (2020-02-06)

  • 修复 ImmutableContainer.__delitem__:为了删除一个对象的所有版本,删除方法使用内部 super() 调用来获取查询过滤器。这最终忽略了子类过滤器,导致删除跨越容器边界。

    作为解决方案,已引入新的 _pj_get_resolve_filter_all_versions 方法,该方法返回容器中所有版本的查询。现在 _pj_get_resolve_filter 方法使用另一个方法并简单地添加“最新版本”约束。所有子容器现在都应该覆盖 _pj_get_resolve_filter_all_versions 而不是 _pj_get_resolve_filter

1.2.1 (2020-02-02)

  • 修复 ImmutableContainer.__delitem__:它没有删除已删除对象的版本。

  • 修复 ImmutableContainer.rollbackToRevision:它回滚了所有对象到指定的版本。

1.2.0 (2020-01-20)

  • 扩展了 IRevisionedImmutableManager 以支持高效的版本管理。

    • 添加了 getNumberOfRevisions(obj) 方法,以返回给定对象可用的版本数。请注意,这并不一定等于最新版本号。

    • 扩展了 getRevisionHistory() 以支持多个新参数,以支持过滤、排序和分批处理。

      过滤参数

      • creator:修订版本的创建者必须匹配参数。

      • comment:注释必须包含参数作为子串。

      • startBefore: 修订必须在给定日期/时间之前开始。

      • startAfter: 修订必须在给定日期/时间之后开始。

      排序参数

      • reversed: 当为 true 时,历史记录将以相反顺序返回

        按时间顺序,特别是最新修订首先列出。

      批处理参数

      • batchStart: 批处理开始的位置。

      • batchSize: 批处理的大小。因此,它是可迭代对象的最大长度。

  • 为简单修订管理和 pjpersist 容器提供了新的参数实现。

  • 声明 ImmutableContainer 实现了 IRevisionedImmutableManager

  • 测试覆盖率提高到 100%。

1.1.1 (2019-06-11)

  • datetime 类作为系统不可变类型。

1.1.0 (2019-05-31)

  • IRevisionedImmutable 中引入了 __im_version__ 并使用它代替时间戳来创建修订的按时间顺序。 (时间戳可能在服务器之间略有不同,并导致不良历史。)

  • 不要在 RevisionedImmutableBase 中重复实现 __im_update__()。 使用 __im_[before|after]_update__() 来执行所有与修订相关的任务。

  • 调整 copy() 的实现以适用于 ImmutableListImmutableDict

  • 正确实现 ImmutableDict.fromkeys()

1.0.5 (2019-05-31)

  • 修复 ImmutableList.copy() 以在锁定时正常工作。这允许仅创建浅拷贝,因为任何更新都会导致深拷贝,从而保证不可变性。

  • 实现了 ImmutableDict.copy()。在 ImmutableDict.fromkeys() 上引发错误。

  • ImmutableContainer 还需要一个更新的 _pj_column_fields 列表。

  • 一些小的测试修复。

  • 一些小的文档修复和代码注释改进。

1.0.4 (2019-05-30)

  • 添加 API 文档。

1.0.3 (2019-05-30)

  • 将文档移动到 Read the Docs。

1.0.2 (2019-05-30)

  • 添加一些可读的文档。

  • 添加了高级 shoobx.immutable.update(im, *args, **kw) 函数。

  • ImmutableSet 实现 __repr__() 以模仿 ImmutableDictImmutableList 的行为。

1.0.1 (2019-05-30)

  • 修复包描述。

1.0.0 (2019-05-30)

  • 不可变类型、不可变字典、不可变集合、不可变列表

  • 带修订管理器示例实现的修订不可变

  • 可选:pjpersist 对不可变对象的支持。需要 pjpersist>=1.7.0。

  • 初始版本

项目详情


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。

源分布

shoobx.immutable-2.0.3.tar.gz (42.0 kB 查看哈希值)

上传时间

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面