Metadata-Version: 2.1
Name: cynamedtuple
Version: 0.1.0
Summary: Memory efficient and fast namedtuple implementation using Cython
Home-page: https://github.com/realead/cynamedtuple
Author: Egor Dranischnikow
License: MIT
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 a `cynamedtuple`, thus the types of `cynamedtuple` 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
        
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Description-Content-Type: text/markdown
