Memory efficient and fast namedtuple implementation using Cython
Project description
cynamedtuple
Memory efficient and fast namedtuple
implementation using Cython
.
Installation
To install last released version:
pip install cynamedtuple
As cynamedtuple
uses Cython
under the hood, right C-compler/tool-chain is needed in order to be able to create cynamedtuple
s.
To install the most current version use:
pip install https://github.com/realead/cynamedtuple/zipball/master
The necessary Cython
-module will be installed as well, if not already in the installation.
Usage
When providing the types of fields, the resulting tuple is not only named but also typed, i.e. the underlying fields backed by corresponding c-types thus needing less memory:
from cynamedtuple import typed_namedtuple
MyStruct = typed_namedtuple("MyStruct", dict(a="int", b="int", c="int"), defaults=[2,3])
s = MyStruct(5)
print(s.a, s.b, s.c) # results in 5 2 3
print(s[0], s[1], s[-1]) # results in 5 2 3
For Python versions with non-ordered dict
s (i.e. prior to Py3.6), version with name-type-pairs iterable can be used:
...
typed_namedtuple("MyStruct", [("a","int"), ("b","int"), ("c","int")])
...
When the fields cannot be statically typed, untyped_namedtuple
can be used, which uses slightly less memory and is somewhat faster than Python's original namedtuple
:
from cynamedtuple import untyped_namedtuple
MyStruct = untyped_namedtuple("MyStruct", ["a", "b", "c"], defaults=[2,3])
s = MyStruct(5)
print(s.a, s.b, s.c) # results in 5 2 3
print(s[0], s[1], s[-1]) # results in 5 2 3
Performance
Let's compare the performance of the following implementation
P=collections.namedtuple("P",["a", "b"])
T=cynamedtuple.typed_namedtuple("T", [("a", "int"), ("b", "int")])
U=cynamedtuple.untyped_namedtuple("U", ["a", "b"])
with the built-in (unnamed) tuple
.
Memory usage
Memory usage depends on the used types, using int
instead of Python's integer means 3-4 times smaller memory footprint. For 1e7
elements in a list following memory was used:
Class | Used memory (in MB) |
---|---|
typed(T) | 308 |
untyped(U) | 927 |
Python's(P) | 1082 |
tuple | 1006 |
Timings
Creation
For creation of 1e6
elements, typed cynamedtuple is almost as fast as usual tuple and about 4 times faster than Python's namedtuple
:
Class | Times |
---|---|
typed(T) | 128 ms |
untyped(U) | 171 ms |
Python's(P) | 504 ms |
tuple | 118 ms |
Accessing fields
For accessing a field, typed and untyped versions are about 30% faster than Python's namedtuple
but slightly slower than the usual tuple
:
Class | Times |
---|---|
typed(T) | 51.5 ns |
untyped(U) | 45.5 ns |
Python's(P) | 68.4 ns |
tuple | 49.9 ns |
Accessing via index
Warning: cynamedtuple
s aren't optimized for access via index - it is linear in number of fields, thus should not be used if there are many fields.
Producing pyx-code
Under the hood cynamedtuple uses string code snippets from Cython (aka cython.inline
), and with that some constrains come into play:
- Cython doesn't not yet supporting any cimports/includes from string code snippets
- it is not possible to define any types via
ctypedef
e.g.ctypedef int myint
and use them in acynamedtuple
, thus the types ofcynamedtuple
are limited to the built-in types.
A workaround is to use typed_namedtuple_cycode
to produce the Cython code and to build a cython module from it. Use cython_header
-argument to insert needed definitions, e.g.
typed_namedtuple_cycode("A", (("a", "myint"),), cython_header = ["ctypedef int myint"])
will yield the following cython-code:
ctypedef int myint
cdef class A:
cdef public myint a
def __init__(self,a):
self.a = a
def __getitem__(self, i):
if i==0 or i==-1: return self.a
raise IndexError('tuple index out of range')
There is also untyped_namedtuple_cycode
-function as well.
Trivia:
- This project was inspired by the following SO-question: https://stackoverflow.com/q/65159938/5769463.
- While Python's
namedtuple
was an inspiration,cynamedtuple
isn't a simple drop-in replacement. - While cnamedtuple (https://pypi.org/project/cnamedtuple/) is all about speed,
cynamedtuple
is more about smaller memory footprint.
History:
- 0.1.0: 13.12.2020:
- introducing basic functionality
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file cynamedtuple-0.1.0.tar.gz
.
File metadata
- Download URL: cynamedtuple-0.1.0.tar.gz
- Upload date:
- Size: 4.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/49.6.0.post20200814 requests-toolbelt/0.9.1 tqdm/4.49.0 CPython/3.7.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 10d4b43436a165e913a9baa99aa2a1a9def7908f91f3587f31f117eb15c4055d |
|
MD5 | c8843ef37cb07ea8aa6655eb208d1bb4 |
|
BLAKE2b-256 | 7578ca279e19dd0af0dd8e6f73ca9cf3aea76704a9111f90da0eb16efde94822 |