{ "info": { "author": "Arnau Orriols", "author_email": "dev@arnauorriols.com", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "Programming Language :: Python :: 2 :: Only" ], "description": "Cheap namedtuple implementation (Python 2.7)\n============================================\n\nNamedtuples are a neat goody of Python, but they have one big caveat. In\norder to be precise with the type definition, they compile with exec a\nstring template, formated with the variables given in the namedtuple()\nfunction factory. This compilation is very expensive computation-wise,\nand in practice can be spared if needed for performance reasons.\n\nAn `issue `__ was opened years ago in\nthe Python bug tracker but it got rejected, arguing that the official\nimplementation is clearer and more maintainable. This is true, but there\nare cases where performance is key, and the current implementation using\nexec is just not an option.\n\nIf you need to define new namedtuple types dynamically, and you have\nhigh performance constraints, this is for you.\n\nThere are multiple versions out there, using\n`metaclasses `__, or\n`metaclasses `__,\nor\n`ABC `__\n\nThis versions is simpler. Just define a new class closed-over by the\nfactory function.\n\nUnittests from cPython2.7 implementation are copied here to assert that\nthe same expected behaviour is honored.\n\nInstall\n-------\n\n.. code:: bash\n\n pip install cheapnamedtuple\n\nUsage\n-----\n\nFor the purist, the ``namedtuple`` implementation is 3.75x faster than\nPython's implementation, while honouring 100% of the Python's\nimplementation behaviour, including docstrings and everything else\n(corroborated by unit tests):\n\n.. code:: python\n\n >>> from cheapnamedtuple import namedtuple\n >>> Point = namedtuple('Point', ['x', 'y'])\n >>> Point.__doc__ # docstring for the new class\n 'Point(x, y)'\n >>> p = Point(11, y=22) # instantiate with positional args or keywords\n >>> p[0] + p[1] # indexable like a plain tuple\n 33\n >>> x, y = p # unpack like a regular tuple\n >>> x, y\n (11, 22)\n >>> p.x + p.y # fields also accessible by name\n 33\n >>> d = p._asdict() # convert to a dictionary\n >>> d['x']\n 11\n >>> Point(**d) # convert from a dictionary\n Point(x=11, y=22)\n >>> p._replace(x=100) # _replace() is like str.replace() but targets named fields\n Point(x=100, y=22)\n\nFor the practical, a ``cheapnamedtuple`` implementation is 26.6x faster\nthan the Python's implementation, while still honouring all the public\nbehaviour (corroborated by doctests), and still supporting copy and\npickle. The only caveats identified so far are:\n\n- The docstring of the type generated by the cheapnamedtuple factory\n cannot be generated ad-hoc for it\n- Some typechecking has been trade in favor of performance (see\n test\\_name\\_fixer test case)\n\n.. code:: python\n\n >>> from cheapnamedtuple import cheapnamedtuple\n >>> Point = cheapnamedtuple('Point', ['x', 'y'])\n >>> Point.__doc__ # docstring for the new class\n 'Point(x, y)'\n >>> p = Point(11, y=22) # instantiate with positional args or keywords\n >>> p[0] + p[1] # indexable like a plain tuple\n 33\n >>> x, y = p # unpack like a regular tuple\n >>> x, y\n (11, 22)\n >>> p.x + p.y # fields also accessible by name\n 33\n >>> d = p._asdict() # convert to a dictionary\n >>> d['x']\n 11\n >>> Point(**d) # convert from a dictionary\n Point(x=11, y=22)\n >>> p._replace(x=100) # _replace() is like str.replace() but targets named fields\n Point(x=100, y=22)\n\nCompatibility\n=============\n\nCurrently only tested in Python 2.7\n\nBenchmarking\n============\n\nPython's stdlib implementation:\n\n.. code:: bash\n\n $python -m timeit -vvvv \"from collections import namedtuple\" \"A = namedtuple('A', ['foo', 'bar', 'foobar'])\" \"a = A(1, 2, 3)\" \"a.bar\"\n 10 loops -> 0.00922394 secs\n 100 loops -> 0.0595999 secs\n 1000 loops -> 0.350676 secs\n raw times: 0.328964 0.33169 0.327519\n 1000 loops, best of 3: 327.519 usec per loop\n\n``namedtuple`` implementation:\n\n.. code:: bash\n\n $ python -m timeit -vvvv \"from cheapnamedtuple import namedtuple\" \"A = namedtuple('A', ['foo', 'bar', 'foobar'])\" \"a = A(1, 2, 3)\" \"a.bar\"\n 10 loops -> 0.00332594 secs\n 100 loops -> 0.01106 secs\n 1000 loops -> 0.09164 secs\n 10000 loops -> 0.955008 secs\n raw times: 0.929455 0.872804 0.904877\n 10000 loops, best of 3: 87.2804 usec per loop\n\n``cheapnamedtuple`` implementation:\n\n.. code:: bash\n\n $ python -m timeit -vvvv \"from cheapnamedtuple import cheapnamedtuple\" \"A = cheapnamedtuple('A', ['foo', 'bar', 'foobar'])\" \"a = A(1, 2, 3)\" \"a.bar\"\n 10 loops -> 0.00241184 secs\n 100 loops -> 0.00281 secs\n 1000 loops -> 0.0245481 secs\n 10000 loops -> 0.156194 secs\n 100000 loops -> 1.25612 secs\n raw times: 1.23459 1.23159 1.23687\n 100000 loops, best of 3: 12.3159 usec per loop\n\nUsing metaclass version found\n`here `__:\n\n.. code:: bash\n\n $ python -m timeit -vvvv \"from metanamedtuple import namedtuple\" \"A = namedtuple('A', ['foo', 'bar', 'foobar'])\" \"a = A(1, 2, 3)\" \"a.bar\"\n 10 loops -> 0.00334907 secs\n 100 loops -> 0.0108609 secs\n 1000 loops -> 0.088969 secs\n 10000 loops -> 1.25756 secs\n raw times: 1.2868 1.24004 1.25383\n 10000 loops, best of 3: 124.004 usec per loop", "description_content_type": null, "docs_url": null, "download_url": null, "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/arnauorriols/cheapnamedtuple", "keywords": "namedtuple exec performance", "license": "MIT License", "maintainer": null, "maintainer_email": null, "name": "cheapnamedtuple", "package_url": "https://pypi.org/project/cheapnamedtuple/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/cheapnamedtuple/", "project_urls": { "Homepage": "https://github.com/arnauorriols/cheapnamedtuple" }, "release_url": "https://pypi.org/project/cheapnamedtuple/1.1.2/", "requires_dist": null, "requires_python": null, "summary": "Faster reimplementation of stdlib collections.namedtuple", "version": "1.1.2" }, "last_serial": 2240670, "releases": { "1.1.2": [ { "comment_text": "", "digests": { "md5": "db9051fa627bc31fac3885c6e537bdde", "sha256": "669f7b8ba56a3a01503fd36eaf8a923f2cc2d209b8ec9a7dadf9c7c2a97e21c9" }, "downloads": -1, "filename": "cheapnamedtuple-1.1.2.tar.gz", "has_sig": false, "md5_digest": "db9051fa627bc31fac3885c6e537bdde", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5854, "upload_time": "2016-07-24T10:56:39", "url": "https://files.pythonhosted.org/packages/b5/7b/90a3658845ce21e25b02a45625983fc14017b1066a55140194e0a6ddff05/cheapnamedtuple-1.1.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "db9051fa627bc31fac3885c6e537bdde", "sha256": "669f7b8ba56a3a01503fd36eaf8a923f2cc2d209b8ec9a7dadf9c7c2a97e21c9" }, "downloads": -1, "filename": "cheapnamedtuple-1.1.2.tar.gz", "has_sig": false, "md5_digest": "db9051fa627bc31fac3885c6e537bdde", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5854, "upload_time": "2016-07-24T10:56:39", "url": "https://files.pythonhosted.org/packages/b5/7b/90a3658845ce21e25b02a45625983fc14017b1066a55140194e0a6ddff05/cheapnamedtuple-1.1.2.tar.gz" } ] }