namedtuple的可变变体 -- recordclass,支持赋值、紧凑数据类和其他节省内存的变体。
项目描述
# Recordclass library
Recordclass 是一个 MIT 许可 的 python 库。它最初是为了解决快速“可变”的 namedtuple
替代方案的问题而开始的“概念验证”(参见 stackoverflow 上的问题)。它进一步发展,以提供更多节省内存、快速和灵活的类型。
Recordclass 库提供类似记录/数据的类,默认情况下不参与循环 垃圾回收(GC)机制,但支持仅 引用计数 的垃圾回收。此类实例没有内存中的 PyGC_Head
前缀,这减少了它们的大小,并且实例创建和分配的路径要快一些。在需要尽可能限制对象大小时,这可能会很有意义,前提是它们永远不会成为应用程序中引用循环的一部分。例如,当对象按照惯例代表具有简单类型值的字段记录时(例如 int
、float
、str
、date
/time
/datetime
、timedelta
等)。
为了说明这一点,考虑一个带有类型提示的简单类
class Point:
x: int
y: int
通过默许协议,类 Point
的实例应该具有类型为 int
的属性 x
和 y
。分配其他类型的值,这些值不是 int
的子类,应被视为违反协议。
其他例子是非递归数据结构,其中所有叶元素表示原子类型的值。当然,在 Python 中,没有阻止你在脚本或应用程序代码中创建引用循环。但许多情况下,只要开发者理解自己在做什么,并谨慎地在代码库中使用此类,就可以避免这种情况。另一种选择是使用静态代码分析器以及类型注解来监控对类型提示的遵守。
该库建立在基类 dataobject
之上。类型为特殊的元类 datatype
。它控制子类的创建,这些子类不会参与循环 GC,并且默认不包含 PyGC_Head
-前缀、__dict__
和 __weakref__
。因此,此类实例所需的内存较少。其内存占用与具有 __slots__
的类实例的内存占用相似,但不包含 PyGC_Head
。因此,内存大小的差异等于 PyGC_Head
的大小。它还调整实例的 basicsize
,创建字段的描述符等。通过 class statement
创建的 dataobject
的所有子类都支持类似 attrs
/dataclasses
的 API。例如
from recordclass import dataobject, astuple, asdict
class Point(dataobject):
x:int
y:int
>>> p = Point(1, 2)
>>> astuple(p)
(1, 2)
>>> asdict(p)
{'x':1, 'y':2}
recordclass
工厂创建基于 dataobject
的子类,具有指定的字段和类似 namedtuple
的 API。默认情况下,它也不会参与循环 GC。
>>> from recordclass import recordclass
>>> Point = recordclass('Point', 'x y')
>>> p = Point(1, 2)
>>> p.y = -1
>>> print(p._astuple)
(1, -1)
>>> x, y = p
>>> print(p._asdict)
{'x':1, 'y':-1}
它还提供了一个用于创建具有指定字段名的 dataobject
子类的工厂函数 make_dataclass
。这些子类支持类似 attrs
/dataclasses
的 API。它相当于使用 class statement
创建 dataobject
的子类。例如
>>> Point = make_dataclass('Point', 'x y')
>>> p = Point(1, 2)
>>> p.y = -1
>>> print(p.x, p.y)
1 -1
如果想要使用某个序列进行初始化,则
>>> p = Point(*sequence)
还有一个用于创建可以视为简单对象紧凑数组的 dataobject
子类的工厂函数 make_arrayclass
。例如
>>> Pair = make_arrayclass(2)
>>> p = Pair(2, 3)
>>> p[1] = -1
>>> print(p)
Pair(2, -1)
该库还提供了 lightlist
(不可变)和 litetuple
类,它们被视为为了节省内存而类似于列表和元组的轻量级容器。它们也不应该参与循环 GC。可变版本的 litetuple 称为 mutabletuple
。例如
>>> lt = litetuple(1, 2, 3)
>>> mt = mutabletuple(1, 2, 3)
>>> lt == mt
True
>>> mt[-1] = -3
>>> lt == mt
False
>>> print(sys.getsizeof((1,2,3)), sys.getsizeof(litetuple(1,2,3)))
64 48
注意,如果想要从某些可迭代对象创建 litetuple
或 mutabletuple
,则
>>> seq = [1,2,3]
>>> lt = litetuple(*seq)
>>> mt = mutabletuple(*seq)
内存占用
以下表格解释了基于 dataobject
的对象和 litetuples 的内存占用
tuple/namedtuple | 带有 __slots__ 的类 | recordclass/dataobject | litetuple/mutabletuple |
---|---|---|---|
g+b+s+n×p | g+b+n×p | b+n×p | b+s+n×p |
其中
- b = sizeof(PyObject)
- s = sizeof(Py_ssize_t)
- n = 项数
- p = sizeof(PyObject*)
- g = sizeof(PyGC_Head)
这在您绝对确定不会出现引用循环的情况下很有用。例如,当所有字段值都是原子类型实例时。结果,实例的大小减少了 24-32 字节(CPython 3.4-3.7)和 16 字节(CPython >=3.8)。
性能计数器
以下表格是使用 tools/perfcounts.py
脚本测量的性能计数器
- recordclass 0.21,python 3.10,debian/testing linux,x86-64
id | 大小 | 新 | getattr | setattr | getitem | setitem | getkey | setkey | iterate | copy |
---|---|---|---|---|---|---|---|---|---|---|
litetuple | 48 | 0.18 | 0.2 | 0.33 | 0.19 | |||||
mutabletuple | 48 | 0.18 | 0.21 | 0.21 | 0.33 | 0.18 | ||||
tuple | 64 | 0.24 | 0.21 | 0.37 | 0.16 | |||||
namedtuple | 64 | 0.75 | 0.23 | 0.21 | 0.33 | 0.21 | ||||
class+slots | 56 | 0.68 | 0.29 | 0.33 | ||||||
dataobject | 40 | 0.25 | 0.23 | 0.29 | 0.2 | 0.22 | 0.33 | 0.2 | ||
dataobject+gc | 56 | 0.27 | 0.22 | 0.29 | 0.19 | 0.21 | 0.35 | 0.22 | ||
dict | 232 | 0.32 | 0.2 | 0.24 | 0.35 | 0.25 | ||||
dataobject+map | 40 | 0.25 | 0.23 | 0.3 | 0.29 | 0.29 | 0.32 | 0.2 |
- recordclass 0.21,python 3.11,debian/testing linux,x86-64
id | 大小 | 新 | getattr | setattr | getitem | setitem | getkey | setkey | iterate | copy |
---|---|---|---|---|---|---|---|---|---|---|
litetuple | 48 | 0.11 | 0.11 | 0.18 | 0.09 | |||||
mutabletuple | 48 | 0.11 | 0.11 | 0.12 | 0.18 | 0.08 | ||||
tuple | 64 | 0.1 | 0.08 | 0.17 | 0.1 | |||||
namedtuple | 64 | 0.49 | 0.13 | 0.11 | 0.17 | 0.13 | ||||
class+slots | 56 | 0.31 | 0.06 | 0.06 | ||||||
dataobject | 40 | 0.13 | 0.06 | 0.06 | 0.11 | 0.12 | 0.16 | 0.12 | ||
dataobject+gc | 56 | 0.14 | 0.06 | 0.06 | 0.1 | 0.12 | 0.16 | 0.14 | ||
dict | 184 | 0.2 | 0.12 | 0.13 | 0.19 | 0.13 | ||||
dataobject+map | 40 | 0.12 | 0.07 | 0.06 | 0.15 | 0.16 | 0.16 | 0.12 | ||
class | 56 | 0.35 | 0.06 | 0.06 |
- recordclas 0.21,python3.12,debian/testing linux,x86-64
id | 大小 | 新 | getattr | setattr | getitem | setitem | getkey | setkey | iterate | copy |
---|---|---|---|---|---|---|---|---|---|---|
litetuple | 48 | 0.13 | 0.12 | 0.19 | 0.09 | |||||
mutabletuple | 48 | 0.13 | 0.11 | 0.12 | 0.18 | 0.09 | ||||
tuple | 64 | 0.11 | 0.09 | 0.16 | 0.09 | |||||
namedtuple | 64 | 0.52 | 0.13 | 0.11 | 0.16 | 0.12 | ||||
class+slots | 56 | 0.34 | 0.08 | 0.07 | ||||||
dataobject | 40 | 0.14 | 0.08 | 0.08 | 0.11 | 0.12 | 0.17 | 0.12 | ||
dataobject+gc | 56 | 0.15 | 0.08 | 0.07 | 0.12 | 0.12 | 0.17 | 0.13 | ||
dict | 184 | 0.19 | 0.11 | 0.14 | 0.2 | 0.12 | ||||
dataobject+map | 40 | 0.14 | 0.08 | 0.08 | 0.16 | 0.17 | 0.17 | 0.12 | ||
class | 48 | 0.41 | 0.08 | 0.08 |
recordclass
的主要仓库位于GitHub。
这里还有一个简单的示例。
更多示例可以在examples文件夹中找到。
快速入门
安装
从源目录安装
安装
>>> python3 setup.py install
运行测试
>>> python3 test_all.py
从PyPI安装
安装
>>> pip3 install recordclass
运行测试
>>> python3 -c "from recordclass.test import *; test_all()"
使用dataobject的快速入门
Dataobject
是用于创建具有快速实例创建和较小内存占用数据类的基类。它们提供类似dataclass
的API。
首先加载库存
>>> from recordclass import dataobject, asdict, astuple, as_dataclass, as_record
以某种方式定义类
class Point(dataobject):
x: int
y: int
或者
@as_dataclass()
class Point:
x: int
y: int
或者
@as_record
def Point(x:int, y:int): pass
或者
>>> Point = make_dataclass("Point", [("x",int), ("y",int)])
或者
>>> Point = make_dataclass("Point", {"x":int, "y",int})
字段的注解被定义为__annotations__
中的字典
>>> print(Point.__annotations__)
{'x': <class 'int'>, 'y': <class 'int'>}
存在默认文本表示
>>> p = Point(1, 2)
>>> print(p)
Point(x=1, y=2)
实例具有CPython对象可能的最小内存占用,其中只包含Python对象
>>> sys.getsizeof(p) # the output below for python 3.8+ (64bit)
40
>>> p.__sizeof__() == sys.getsizeof(p) # no additional space for cyclic GC support
True
默认情况下实例是可变的
>>> p_id = id(p)
>>> p.x, p.y = 10, 20
>>> id(p) == p_id
True
>>> print(p)
Point(x=10, y=20)
存在asdict
和astuple
函数,用于转换为dict
和tuple
>>> asdict(p)
{'x':10, 'y':20}
>>> astuple(p)
(10, 20)
默认情况下,dataobject的子类是可变的。如果想要使其不可变,则可以使用选项readonly=True
class Point(dataobject, readonly=True):
x: int
y: int
>>> p = Point(1,2)
>>> p.x = -1
. . . . . . . . . . . . .
TypeError: item is readonly
默认情况下,dataobject的子类不是可迭代的。如果想要使其可迭代,则可以使用选项iterable=True
class Point(dataobject, iterable=True):
x: int
y: int
>>> p = Point(1,2)
>>> for x in p: print(x)
1
2
也支持默认值:
class CPoint(dataobject):
x: int
y: int
color: str = 'white'
或者
>>> CPoint = make_dataclass("CPoint", [("x",int), ("y",int), ("color",str)], defaults=("white",))
>>> p = CPoint(1,2)
>>> print(p)
Point(x=1, y=2, color='white')
但是
class PointInvalidDefaults(dataobject):
x:int = 0
y:int
不允许。没有默认值的字段不能出现在有默认值的字段之后。
从0.21版开始,存在copy_default
选项(在创建实例时分配默认值的副本)
class Polygon(dataobject, copy_default=True):
points: list = []
>>> pg1 = Polygon()
>>> pg2 = Polygon()
>>> assert pg1.points == pg2.points
True
>>> assert id(pg1.points) != id(pg2.points)
True
从0.21版开始,Factory
允许设置计算默认值的工厂函数
from recordclass import Factory
class A(dataobject, copy_default=True):
x: tuple = Factory( lambda: (list(), dict()) )
>>> a = A()
>>> b = A()
>>> assert a.x == b.x
True
>>> assert id(a.x[0]) != id(b.x[0])
True
>>> assert id(a.x[1]) != id(b.x[1])
True
如果有人想定义类属性,则可以使用ClassVar
技巧
class Point(dataobject):
x:int
y:int
color:ClassVar[int] = 0
>>> print(Point.__fields__)
('x', 'y')
>>> print(Point.color)
0
如果ClassVar
属性的默认值未指定,则它将仅从__fields___
中排除。
从Python 3.10开始,默认指定__match_args__
,因此__match_args__
== __fields__
。用户可以在定义时定义它自己的
class User(dataobject):
first_name: str
last_name: str
age: int
__match_args__ = 'first_name', 'last_name'
或者
from recordclass import MATCH
class User(dataobject):
first_name: str
last_name: str
_: MATCH
age: int
或者
User = make_dataclass("User", "first_name last_name * age")
使用recordclass的快速入门
recordclass
工厂函数旨在创建支持namedtuple
API的类,可以是可变的和不可变的,提供快速实例创建和最小内存占用。
首先加载库存
>>> from recordclass import recordclass
使用recordclass
的示例
>>> Point = recordclass('Point', 'x y')
>>> p = Point(1,2)
>>> print(p)
Point(1, 2)
>>> print(p.x, p.y)
1 2
>>> p.x, p.y = 1, 2
>>> print(p)
Point(1, 2)
>>> sys.getsizeof(p) # the output below is for 64bit cpython3.8+
32
使用类语句和类型提示的示例
>>> from recordclass import RecordClass
class Point(RecordClass):
x: int
y: int
>>> print(Point.__annotations__)
{'x': <class 'int'>, 'y': <class 'int'>}
>>> p = Point(1, 2)
>>> print(p)
Point(1, 2)
>>> print(p.x, p.y)
1 2
>>> p.x, p.y = 1, 2
>>> print(p)
Point(1, 2)
默认情况下,基于recordclass
的类实例不参与循环GC,因此它们比基于namedtuple
的实例更小。如果想要在具有引用循环的场景中使用它,则必须使用选项gc=True
(默认为gc=False
)
>>> Node = recordclass('Node', 'root children', gc=True)
或者
class Node(RecordClass, gc=True):
root: 'Node'
chilren: list
recordclass
工厂还可以指定字段的类型
>>> Point = recordclass('Point', [('x',int), ('y',int)])
或者
>>> Point = recordclass('Point', {'x':int, 'y':int})
使用基于dataobject的类与映射协议
class FastMapingPoint(dataobject, mapping=True):
x: int
y: int
或者
FastMapingPoint = make_dataclass("FastMapingPoint", [("x", int), ("y", int)], mapping=True)
>>> p = FastMappingPoint(1,2)
>>> print(p['x'], p['y'])
1 2
>>> sys.getsizeof(p) # the output below for python 3.10 (64bit)
32
使用基于dataobject的类处理无引用循环的递归数据
存在deep_dealloc
选项(默认值为False
)用于递归数据结构的分配
class LinkedItem(dataobject):
val: object
next: 'LinkedItem'
class LinkedList(dataobject, deep_dealloc=True):
start: LinkedItem = None
end: LinkedItem = None
def append(self, val):
link = LinkedItem(val, None)
if self.start is None:
self.start = link
else:
self.end.next = link
self.end = link
如果没有deep_dealloc=True
,则在链表长度太大时,LinkedList
实例的分配将失败。但可以通过链表的__del__
方法来清除链表解决
def __del__(self):
curr = self.start
while curr is not None:
next = curr.next
curr.next = None
curr = next
当deep_dealloc=True
时,存在内建的更快地分配方法,使用终结机制。在这种情况下,不需要__del__
方法来清除链表。
注意:对于具有
gc=True
的类,此方法被禁用:在这些情况下使用Python的循环GC。
有关更多详细信息,请参阅笔记本example_datatypes。
变更
0.22.1:
-
添加
pyproject.toml
。 -
添加
pytest.ini
以运行pytest
。>>> pip3 install -e . >>> pytest
0.22.0.3:
- 重命名
examples\test_*.py
文件,因为它们被pytest
检测为测试。 - 修复了
litelist
在0.22.0.2
后的段错误。
0.22.0.2
- 在GitHub上使用正确的标签发布。
0.22.0.1
- 使用
as_dataclass
修复回归问题。
0.22
- 为应该表现得更像简单数据结构的子类添加一个基类
datastruct
。 - 修复与
__match_args__
相关的错误 (#6)。 - 开始支持Python 3.13。
0.21.1
-
允许指定
__match_args__
。例如,class User(dataobject): first_name: str last_name: str age: int __match_args__ = 'first_name', 'last_name'
或者
User = make_dataclass("User", "first_name last_name * age")
-
为被视为结构的
def
风格的数据类声明添加@as_record
适配器。例如@as_record() def Point(x:float, y:float, meta=None): pass >>> p = Point(1,2) >>> print(p) Point(x=1, y=2, meta=None)
几乎等同于
Point = make_dataclass('Point', [('x':float), ('y',float),'meta'], (None,))
-
选项
fast_new
将在0.22版本中移除。它将始终通过创建设置为fast_new=True
。可以指定自己的__new__
,例如class Point(dataobject): x:int y:int def __new__(cls, x=0, y=0): return dataobject.__new__(cls, x, y)
-
修复与
_PyUnicodeWriter
相关的错误,针对Python 3.13。
0.21
-
添加一个新的选项
copy_default
(默认值为False
),允许为字段分配默认值的副本。例如class A(dataobject, copy_default=True): l: list = [] a = A() b = A() assert(a.l == b.l) assert(id(a.l) != id(b.l))
-
允许继承选项:
copy_default
、gc
、iterable
。例如class Base(dataobject, copy_default=True): pass class A(Base): l: list = [] a = A() b = A() assert a.l == b.l assert id(a.l) != id(b.l)
-
为默认值添加
Factory
以指定工厂函数。例如from recordclass import Factory class A(dataobject): x: tuple = Factory(lambda: (list(), dict())) a = A() b = A() assert a.x == ([],{}) assert id(a.x) != id(b.x) assert id(a.x[0]) != id(b.x[0]) assert id(a.x[1]) != id(b.x[1]) from recordclass import Factory class A(dataobject, copy_default=True): l: list = [] x: tuple = Factory(lambda: (list(), dict())) a = A() b = A() assert a.x == ([],{}) assert id(a.x) != id(b.x) assert a.l == [] assert id(a.l) != id(b.l)
- Recordclass支持Python 3.12(在linux/debian 11/12和通过appveyor的windows上测试过)。
0.20.1
- 基于
dataobject
类的类改进了sqlite
的row_factory。 - 将recordclass仓库从
bitbucket
移动到github。
0.20
- 库代码库与Python 3.12兼容(仅在linux上测试过,在appveyor上直到Python 3.12支持)。
- 修复通过
update
函数更新只读属性时的错误。
0.19.2
- 对于具有无效关键字参数的Cls(**kwargs),异常消息更加精确 (#37)。
- 为Python >= 3.11添加参数
immutable_type
。如果immutable_type=True
,则生成的类(不是实例)将是不可变的。如果类不包含用户定义的__init__
和__new__
,则实例创建将更快(通过vectorcall协议)。
0.19.1
- 修复与
C.attr=value
相关的回归问题(默认情况下使用不可变类)。
0.19
-
向
litetuple
和mutabletuple
添加vectorcall协议。 -
向
dataobject
添加vectorcall协议。 -
现在,数据对象的
op.__hash__
默认返回id(op)
。选项hashable=True
使数据对象可以通过值进行散列。 -
现在,基于
dataobject
的类、litetuple
和mutabletuple
从Python 3.11开始支持实例创建和getattr/setattr的代码特殊化。 -
修复当子类具有非平凡的
__init__
时的make
函数。 -
对于具有非平凡
__init__
的基于dataobject
的子类,可能还需要定义__reduce__
。例如def __reduce__(self): from recordclass import dataobject, make tp, args = dataobject.__reduce__(self) return make, (tp, args)
0.18.4
- 修复一个错误 #35,在继承过程中复制字段名称,并将其与类级别属性混合。
- 允许使用ClassVar定义类级别字段。
0.18.3
- 修复字段默认值为元组时的错误。
- 修复默认值传播到子类的问题。
- 修复在dill上下文中序列化的一些问题。
0.18.2
- 当字段具有默认值或kwargs时,略微提高了默认
__init__
的性能。 - 移除实验性的pypy支持:速度慢且难以预测内存占用。
- 排除实验性的cython模块。
0.18.1.1
- 重新打包0.18.1,设置
use_cython=0
0.18.1
-
允许在用户定义的
__init__
方法中初始化字段,而不是在__new__
中(问题29)。如果用户定义了__init__
,则它负责初始化所有字段。请注意,此功能仅适用于可变字段。具有readonly=True
的类的实例必须在默认的__new__
中初始化。例如class A(dataobject): x:int y:int def __init__(self, x, y): self.x = x self.y = y
-
fast_new=True
是默认值。 -
为
sqlite3
添加make_row_factory
。class Planet(dataobject): name:str radius:int >>> con = sql.connect(":memory:") >>> cur = con.execute("SELECT 'Earth' AS name, 6378 AS radius") >>> cur.row_factory = make_row_factory(Planet) >>> row = cur.fetchone() >>> print(row) Planet(name='Earth', radius=6378)
0.18.0.1
- 对于Python < 3.10,排除测试_dataobject_match.py(用于测试
match
语句)。
0.18
- 支持Python 3.11。
- 使数据对象受益于Python 3.11的代码特殊化。
- 修复
__new__
中具有默认值的参数的问题,这些参数没有__repr__
可以解释为创建默认值的有效Python表达式。 - 添加对typing.ClassVar的支持。
- 添加
Py_TPFLAGS_SEQUENCE
和Py_TPFLAGS_MAPPING
。 - 为支持基于数据对象子类的匹配协议,添加
__match_args__
。
0.17.5
- 成功编译、构建和测试了 Python 3.11。
0.17.4
- 修复了 3.11 中缺失
_PyObject_GC_Malloc
的错误。
0.17.3
- 修复了兼容性问题:恢复 gnu98 C 语法。
- 修复了使用 "Py_SIZE(op)" 和 "Py_TYPE(op)" 作为 l-value 的遗留问题。
0.17.2
- 添加了对 Python 3.10 的支持。
- 没有使用 "Py_SIZE(op)" 和 "Py_TYPE(op)" 作为 l-value。
0.17.1
- 修复了 setup.py 中 cython=1 的打包问题。
0.17
-
现在 recordclass 库可以编译为 pypy3,但仍然没有与 pypy3 的完全运行时兼容性。
-
略微提高了
litetuple
/mutabletuple
的性能。 -
略微提高了基于
dataobject
的子类的性能。 -
添加适配器
as_dataclass
。例如@as_dataclass() class Point: x:int y:int
-
模块 _litelist 是用纯 C 实现的。
-
使 dataobject.copy 更快。
0.16.3
-
为 recordclasses 添加了按键赋值的功能。
A = recordclass("A", "x y", mapping=True) a = A(1,2) a['x'] = 100 a['y'] = 200
0.16.2
- 修复了 0.16.1 中的打包错误。
0.16.1
- 添加
dictclass
工厂函数,用于生成具有dict-like
API 且没有字段属性访问的类。特点:快速实例创建,小内存占用。
0.16
-
RecordClass
开始成为具有sequence=True
和类似namedtuple
API 的数据对象的直接子类。对于类创建,使用工厂函数recordclass(name, fields, **kw)
(允许指定类型)代替RecordClass(name, fields, **kw)
。 -
将
make_dataclass
的选项 api='dict' 添加到支持 dict-like API 的类中。 -
现在无法使用 del 或内置的 delattr 从其类中删除 dataobject 的属性。例如
>>> Point = make_dataclass("Point", "x y") >>> del Point.x ........... AttributeError: Attribute x of the class Point can't be deleted
-
现在无法使用 del 或内置的 delattr 删除字段的值。例如
>>> p = Point(1, 2) >>> del p.x ........... AttributeError: The value can't be deleted"
相反,可以使用赋值给 None
>>> p = Point(1, 2) >>> p.x = None
-
略微提高了具有
sequence=True
选项的数据对象类索引访问的性能。
0.15.1
-
现在可以通过类声明中的关键字参数指定选项
readonly
和iterable
。例如class Point(dataobject, readonly=True, iterable=True): x:int y:int
-
添加
update(cls, **kwargs)
函数以更新属性值。
0.15
- 现在库只支持 Python >= 3.6
- 现在可以在类声明中的关键字参数中指定
gc
和fast_new
选项。 - 添加了一个函数
astuple(ob)
,用于将数据对象实例ob
转换为元组。 - 删除基于 datatuple 的类。
- 添加函数
make(cls, args, **kwargs)
以创建类cls
的实例。 - 添加函数
clone(ob, **kwargs)
以克隆数据对象实例ob
。 - 将 structclass 作为 make_dataclass 的别名。
- 为基于数据对象的递归子类实例的分配添加选项 'deep_dealloc' (@clsconfig(deep_dealloc=True))。
0.14.3:
- 现在
dataobject
的子类默认支持可迭代和可哈希协议。
0.14.2:
- 修复了 Python 3.9 的编译问题。
0.14.1:
- 修复了在基于 recordclass 的类中子类化的 hash 问题时。
0.14:
- 为生成的
dataobject
-based 类添加了 doc,以支持inspect.signature
。 - 为快速实例创建添加了
fast_new
参数/选项。 - 修复了
litelist
中的 refleak。 - 修复了
dataobject
/datatuple
的序列协议能力。 - 修复了
StructClass
的类型接口。
0.13.2
- 修复了数据对象的深度复制问题 #14。
0.13.1
- 恢复
join_classes
并添加新函数join_dataclasses
。
0.13.0.1
- 删除冗余的调试代码。
0.13
- 使
recordclass
编译并在 cpython 3.8 上工作。 - 由于 bitbucket 将停止支持 mercurial 存储库,将存储库移动到 git。
- 修复了一些潜在的引用泄露。
0.12.0.1
- 修复了缺失的 .h 文件。
0.12
clsconfig
现在成为调整基于数据对象类的首选装饰器。- 修复了 mutabletuples 的连接问题(问题
#10
)。
0.11.1:
- 现在
dataobject
实例可以更快地分配。
0.11:
- 将
memoryslots
重命名为mutabletuple
. mutabletuple
和immutabletuple
不参与循环垃圾回收。- 添加
litelist
类型用于类似列表的对象,它不参与循环垃圾回收。
0.10.3:
- 引入 DataclassStorage 和 RecordclassStorage。它们允许缓存类并使用它们而无需创建新的类。
- 添加
iterable
装饰器和参数。现在具有字段的 dataobject 默认不可迭代。 - 将
astuple
移动到dataobject.c
。
0.10.2
- 修复了 dataobject 的
__copy__
错误。 - 修复了自 0.8.5 版本以来出现的记录类和结构类的 pickling 错误(感谢 Connor Wolf)。
0.10.1
- 现在默认情况下,如果 dataobject 有字段,则不支持序列协议,但支持迭代。
- 出于可用性原因,默认 argsonly=False。
0.10
- 发明了一个新的工厂函数
make_class
,用于在不支持 GC 的情况下创建不同类型的 dataobject 类。 - 发明了一个新的元类
datatype
和新的基类dataobject
,用于使用class
语句创建 dataobject 类。它禁用了 GC 支持,但可以通过装饰器dataobject.enable_gc
启用。它支持类型提示(Python >= 3.6)和默认值。当类型提示应用于所有数据属性时,它可能不指定__fields__
中的字段名称序列(Python >= 3.6)。 - 现在基于
recordclass
的类也可能不支持循环垃圾回收。这通过PyGC_Head
的大小减少了内存占用。现在默认情况下,基于recordclass
的类不支持循环垃圾回收。
0.9
- 将版本更改为 0.9 以指示一个进步。
- 清理
dataobject.__cinit__
。
0.8.5
- 使基于
arrayclass
的对象支持 setitem/getitem,使基于structclass
的对象能够不支持它们。默认情况下,如之前一样,基于structclass
的对象支持 setitem/getitem 协议。 - 现在只有
dataobject
的实例可以与基于arrayclass
和structclass
的实例进行比较。 - 现在生成的类可以具有哈希性。
0.8.4
- 改进了对结构类和数组类只读模式的支持。
- 为 arrayclass 添加测试。
0.8.3
- 将类型提示支持添加到基于结构类的类中。
0.8.2
- 从
__dict__
类中删除usedict
、gc
和weaklist
。
0.8.1
- 默认情况下,通过从源代码构建
recordclass
来移除 Cython 依赖关系 [问题 #7]。
0.8
- 添加
structclass
工厂函数。它是recordclass
的类似物,但与recordclass
和namedtuple
相比,其实例具有更小的内存占用(目前使用Cython
实现)。 - 添加
arrayclass
工厂函数,该函数生成用于创建固定大小数组的类。这种方法的好处是内存占用也较小(目前使用Cython
实现)。 structclass
工厂现在具有gc
参数。如果gc=False
(默认值),则创建的类的实例将关闭循环垃圾回收支持。- 添加函数
join(C1, C2)
以连接两个基于structclass
的类 C1 和 C2。 - 添加
sequenceproxy
函数以从类实例创建不可变和可哈希的代理对象,这些实例通过索引进行访问(目前使用Cython
实现)。 - 添加通过 idiom
ob['attrname']
访问记录类对象属性的支持(问题 #5)。 - 将
readonly
参数添加到记录类工厂中,以生成不可变的 namedtuple。与collection.namedtuple
相比,它使用与常规记录类相同的描述符来提高性能。
0.7
- 使 mutabletuple 对象的创建更快。作为副作用:当字段数 >= 8 时,记录类实例的创建时间不会大于具有
__slots__
的数据类的实例创建时间。 - 记录类工厂函数现在以与 3.7 版本的 namedtuple 相同的方式创建新的记录类类,没有编译生成的类 Python 源代码。
0.6
- 在recordclass工厂函数中添加对默认值的支持,与Python 3.7中namedtuple相同的新增功能。
0.5
- 版本更改为0.5
0.4.4
- 在RecordClass中添加对默认值的支持(来自Pedro von Hertwig的补丁)
- 为RecordClass添加测试(从python的NamedTuple测试中采用)
0.4.3
- 为Python 3.6添加类型支持(来自Vladimir Bolshakov的补丁)
- 解决内存泄漏问题。
0.4.2
- 修复属性getter/setter中的内存泄漏。
项目详情
下载文件
下载您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。
源分布
构建分布
recordclass-0.22.1.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 80a4c79270edb8fb55bcb96bec0159a292b485c997e2f33b38fdc9e8d6c0c315 |
|
MD5 | 1d99bc016c1679256bef97a35bdd9a4f |
|
BLAKE2b-256 | fdeef45fac2500ef2e401b6073023b59ae6a51e189732ca85409b0dfbb3f51a4 |
recordclass-0.22.1-cp312-cp312-win_amd64.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 06acf38268f753aeda356caeb0c112b0f530030d44984d3a9be49fc08e0a7036 |
|
MD5 | 65bdaf9cf98ea0fc551acb447135fac6 |
|
BLAKE2b-256 | 9ad0a6dac040781568f67b5b28ae9c05a109d7b991cca79092176f8da1ac6746 |
recordclass-0.22.1-cp311-cp311-win_amd64.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 34cfd2e4d7b0ae83f30b422d90290d0f956ed6719a86db4a4e7ef47189397124 |
|
MD5 | 1f921490a005368ec3c62f8bd7eac784 |
|
BLAKE2b-256 | 09cb78e613b1d74329b99f9eed263414b69824b971846fe7eac33c29dddb285f |
recordclass-0.22.1-cp310-cp310-win_amd64.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | a8747246c7c271ce954271777d51a71b6ffbd70f9717949ca58304325787e187 |
|
MD5 | 049f0b466b6f325d669f7b1597966a5e |
|
BLAKE2b-256 | 9a6d37bc8e36088c1a250b62e051570d927d1ef4bae57f6b3d4de58b1451bb83 |
recordclass-0.22.1-cp39-cp39-win_amd64.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 9e1113e43145a5c99cba9579ce48788464a38589fc002f348f8948506c22f3df |
|
MD5 | fdceab81911fa8c39bf51b8cda412c5a |
|
BLAKE2b-256 | deb07058e5127deb63992807e1277db0f722b5467f283741528d061da09f53c4 |
recordclass-0.22.1-cp38-cp38-win_amd64.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 69fa426be6f8f7a5eb2a3d426fc2fc5730a4aff7ab6bc174a166f1e8f94d0ba4 |
|
MD5 | c73a90c75b1919c79f5f511a4e18b866 |
|
BLAKE2b-256 | 88768c931ab9a4f34df37100fbc65d7d4b85427229a47dc06af3d856fc2385b7 |