{ "info": { "author": "Joe Jevnik", "author_email": "joejev@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", "Natural Language :: English", "Operating System :: POSIX", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development :: Pre-processors" ], "description": "``lazy 0.2``\n============\n\n|build status|\n\nI will write this later...\n\nWhat is lazy?\n-------------\n\n``lazy`` is a module for making python `lazily\nevaluated `__ (kinda).\n\n``lazy`` runs under python 3.5 and 3.4.\n\nWhy lazy?\n---------\n\nWhy not lazy?\n\nI think lazy computation is pretty cool, I also think python is pretty\ncool; combining them is double cool.\n\nHow to lazy?\n------------\n\nThere are 3 means of using lazy code:\n\n1. ``lazy_function``\n2. ``run_lazy``\n3. IPython cell and line magics\n\n``lazy_function``\n^^^^^^^^^^^^^^^^^\n\n``lazy_function`` takes a python function and returns a new function that is\nthe lazy version. This can be used as a decorator.\n\nExample:\n\n.. code:: python\n\n @lazy_function\n def f(a, b):\n return a + b\n\nCalling ``f(1, 2)`` will return a ``thunk`` that will add 1 and 2 when it\nneeds to be strict. Doing anything with the returned thunk will keep\nchaining on more computations until it must be strictly evaluated.\n\nLazy functions allow for lexical closures also:\n\n.. code:: python\n\n @lazy_function\n def f(a):\n def g(b):\n return a + b\n return g\n\nWhen we call ``f(1)`` we will get back a ``thunk`` like we would expect;\nhowever, this thunk is wrapping the function ``g``. Because ``g`` was created\nin a lazy context, it will also be a ``lazy_function`` implicitly. This means\nthat ``type(f(1)(2))`` is ``thunk``; but, ``f(1)(2) == 3``.\n\nWe can use strict to strictly evaluate parts of a lazy function, for example:\n\n.. code:: python\n\n >>> @lazy_function\n ... def no_strict():\n ... print('test')\n ...\n >>> strict(no_strict())\n\n\nIn this example, we never forced print, so we never saw the result of the call.\nConsider this function though:\n\n.. code:: python\n\n >>> @lazy_function\n ... def with_strict():\n ... strict(print('test'))\n ...\n >>> strict(with_strict())\n test\n >>> result = with_strict()\n >>> strict(result)\n test\n\nHere we can see how strict works inside of a lazy function. ``strict`` causes\nthe argument to be strictly evaluated, forcing the call to print. We can also\nsee that just calling ``with_strict`` is not enough to evaluate the function,\nwe need to force a dependency on the result.\n\n\n\nThis is implemented at the bytecode level to frontload a large part of the cost\nof using the lazy machinery. There is very little overhead at function call\ntime as most of the overhead was spent at function creation (definiton) time.\n\n``run_lazy``\n^^^^^^^^^^^^\n\nWe can convert normal python into lazy python with the ``run_lazy`` function\nwhich takes a string, the 'name', globals, and locals. This is like ``exec`` or\n``eval`` for lazy python. This will mutate the provided globals and locals so\nthat we can access the lazily evaluated code.\n\nExample:\n\n.. code:: python\n\n >>> code = \"\"\"\n print('not lazy')\n strict(print('lazy'))\n \"\"\"\n >>> run_lazy(code)\n lazy\n\n\nThis also uses the same bytecode manipulation as ``lazy_function`` so they will\ngive the same results.\n\n\nIPython cell and line magics\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nIf you have IPython installed, you may use the cell and line magic machinery to\nwrite and evaluate lazy code. For example:\n\n.. code:: python\n\n In [1]: from lazy import strict\n\n In [2]: %lazy 2 + 2 # line magic acts as an expression\n Out[2]: 4\n\n In [3]: type(_2)\n Out[3]: lazy._thunk.thunk\n\n In [4]: %%lazy # cell magic is treated as a statement\n ...: print('lazy')\n ...: strict(print('strict'))\n ...:\n strict\n\n\n\n``thunk``\n~~~~~~~~~\n\nAt its core, lazy is just a way of converting expressions into a tree\nof deferred computation objects called ``thunk``\\ s. thunks wrap normal\nfunctions by not evaluating them until the value is needed. A ``thunk``\nwrapped function can accept ``thunk``\\ s as arguments; this is how the\ntree is built. Some computations cannot be deferred because there is some state\nthat is needed to construct the thunk, or the python standard defines the\nreturn of some method to be a specific type. These are refered to as 'strict\npoints'. Examples of strict points are ``str`` and ``bool`` because the python\nstandard says that these functions must return an instance of their own\ntype. Most of these converters are strict; however, some other things are\nstrict because it solves recursion issues in the interpreter, like accessing\n``__class__`` on a thunk.\n\n\nCustom Strictness Properties\n----------------------------\n\n``strict`` is actually a type that cannot be put into a ``thunk``. For\nexample:\n\n.. code:: python\n\n >>> type(thunk(strict, 2))\n int\n\nNotice that this is not a thunk, and has been strictly evaluated.\n\nTo create custom strict objects, you can subclass ``strict``. This\nprevents the object from getting wrapped in thunks allowing you to\ncreate strict data structures.\n\nObjects may also define a ``__strict__`` method that defines how to\nstrictly evalueate the object. For example, an object could be defined\nas:\n\n.. code:: python\n\n class StrictFive(object):\n def __strict__(self):\n return 5\n\nThis would make ``strict(StrictFive())`` return 5 instead of an instance\nof ``StrictFive``.\n\n``undefined``\n^^^^^^^^^^^^^\n\n``undefined`` is a value that cannot be strictly evaluated. It is useful as a\nplaceholder for computations.\n\nWe can imagine ``undefined`` in python as:\n\n.. code:: python\n\n @thunk.fromexpr\n @Exception.__new__\n class undefined(Exception):\n def __strict__(self):\n raise self\n\nThis object will raise an instance of itself when it is evaluated.\nThis is presented as an equivalent definition, though it is actually in c to\nmake nicer stack traces.\n\nKnown Issues\n------------\n\nCurrently, the following things are known to not work:\n\nRecursively defined ``thunk``\\ s\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nA recursively defined ``thunk`` is a thunk that appears in its own graph twice.\nFor example:\n\n.. code:: python\n\n >>> a = thunk(lambda: a)\n >>> strict(a)\n\nThis will cause an infinite loop because in order to strictly evaluate ``a``,\nwe will call the function which returns ``a`` which we will try to strictly\nevaluate.\n\nStatus: Bug, might fix.\n\nThis is basically correct, for example:\n\n.. code:: python\n\n >>> a = lambda: a()\n >>> a()\n ...\n RuntimeError: maximum recursion depth exceeded\n\nThe difference in the thunk example is that we will drop into c code to preform\nthe recursion so it will not terminate in a reasonable amount of time.\n\nThe potential fix could be to try to detect these cycles and raise some\nException; however, this might be a very expensive check in the good case\nmaking ``thunk`` evaluation much slower.\n\nGotchas\n-------\n\nI opened it up in the repl, everything is strict!\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nBecause the python spec says the ``__repr__`` of an object must return a\n``str``, a call to ``repr`` must strictly evaluate the contents so that\nwe can see what it is. The repl will implicitly call ``repr`` on things\nto display them. We can see that this is a thunk by doing:\n\n.. code:: python\n\n >>> a = thunk(operator.add, 2, 3)\n >>> type(a)\n lazy.thunk.thunk\n >>> a\n 5\n\nAgain, because we need to compute something to represent it, the repl is\na bad use case for this, and might make it appear at first like this is\nalways strict.\n\n``print`` didn't do anything!\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nUm, what did you think it would do?\n\nIf we write:\n\n.. code:: python\n\n @lazy_function\n def f(a, b):\n print('printing the sum of %s and %s' % (a, b))\n return a + b\n\nThen there is no reason that the print call should be executed. No\ncomputation depends on the results, so it is casually skipped.\n\nThe solution is to force a dependency:\n\n.. code:: python\n\n @lazy_function\n def f(a, b):\n strict(print('printing the sum of %s and %s' % (a, b)))\n return a + b\n\n``strict`` is a function that is used to strictly evaluate things.\nBecause the body of the function is interpreted as lazy python, the\nfunction call is converted into a ``thunk``, and therefore we can\n``strict`` it.\n\nThis is true for *any* side-effectful function call.\n\nx is being evaluated strictly when I think it should be lazy\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThere are some cases where things MUST be strict based on the python\nlanguage spec. Because this is not really a new language, just an\nautomated way of writing really inefficient python, python's rules must\nbe followed.\n\nFor example, ``__bool__``, ``__int__``, and other converters expect that\nthe return type must be a the proper type. This counts as a place where\nstrictness is needed1.\n\nThis might not be the case though, instead, I might have missed\nsomething and you are correct, it should be lazy. If you think I missed\nsomething, open an issue and I will try to address it as soon as\npossible.\n\nSome stateful thing is broken\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nSorry, you are using unmanaged state and lazy evaluation, you deserve\nthis. ``thunks`` cache the normal form so that calling strict the second\ntime will refer to the cached value. If this depended on some stateful\nfunction, then it will not work as intended.\n\nI tried to do x with a ``thunk`` and it broke!\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe library is probably broken. This was written on a whim and I barely\nthought through the use cases.\n\nPlease open an issue and I will try to get back to you as soon as\npossible.\n\nNotes\n~~~~~\n\n1. The function call for the constructor will be made lazy in the\n ``LazyTransformer`` (like ``thunk(int, your_thunk)``), so while this\n is a place where strictness is needed, it can still be 'optimized'\n away.\n\n.. |build status| image:: https://travis-ci.org/llllllllll/lazy_python.svg?branch=master\n :target: https://travis-ci.org/llllllllll/lazy_python", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/llllllllll/lazy_python", "keywords": null, "license": "GPL-2", "maintainer": null, "maintainer_email": null, "name": "lazy_python", "package_url": "https://pypi.org/project/lazy_python/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/lazy_python/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/llllllllll/lazy_python" }, "release_url": "https://pypi.org/project/lazy_python/0.2.1/", "requires_dist": null, "requires_python": null, "summary": "Lazy evaluation for python 3", "version": "0.2.1" }, "last_serial": 2235040, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "a5aaee9dbce7b9b316ace7143c030f8e", "sha256": "c2cfcb49ed538071d537108d5a54c688662351c1e22c7a4584431d65aee03a82" }, "downloads": -1, "filename": "lazy_python-0.1.0.tar.gz", "has_sig": false, "md5_digest": "a5aaee9dbce7b9b316ace7143c030f8e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12248, "upload_time": "2015-02-20T05:28:38", "url": "https://files.pythonhosted.org/packages/47/42/268fdf1d2f832de7b58bffa707e5744581d05a2124ae2b4285653da78049/lazy_python-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "5fc6094d30c48ba8ee087c18a3ca4ddf", "sha256": "6f618b4afae996bccb064086c224dd63349917f97cb63a93355576e825139873" }, "downloads": -1, "filename": "lazy_python-0.1.1.tar.gz", "has_sig": false, "md5_digest": "5fc6094d30c48ba8ee087c18a3ca4ddf", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12318, "upload_time": "2015-02-20T05:31:27", "url": "https://files.pythonhosted.org/packages/7c/37/048c4e1d2a22da7ddc59fb983e99d2370cf91ed7156313584bd48ff88ddb/lazy_python-0.1.1.tar.gz" } ], "0.1.10": [ { "comment_text": "", "digests": { "md5": "1651564558f546abef0c697e24ecd480", "sha256": "ff34d3ab95fa5213670d5a221e3b949cac9b4fbbd8debb4028e083736dd67a04" }, "downloads": -1, "filename": "lazy_python-0.1.10.tar.gz", "has_sig": false, "md5_digest": "1651564558f546abef0c697e24ecd480", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18853, "upload_time": "2015-05-03T02:32:35", "url": "https://files.pythonhosted.org/packages/e2/46/cdefefb3593e611c682f54436c4d9eca300dbbf65c268b8e63bff1feaea8/lazy_python-0.1.10.tar.gz" } ], "0.1.11": [ { "comment_text": "", "digests": { "md5": "4bc8807027de2636fb2db4b56d816cd6", "sha256": "f9fbae3c7088f1bf218d9ad673c1c3adff8745ac075139c7431ad24cd01acc8a" }, "downloads": -1, "filename": "lazy_python-0.1.11.tar.gz", "has_sig": false, "md5_digest": "4bc8807027de2636fb2db4b56d816cd6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18693, "upload_time": "2015-06-28T01:37:54", "url": "https://files.pythonhosted.org/packages/76/ad/732a6ad550cc0fe7b5d71a7901e2e46a4433edf4cae4f521c0803cb43288/lazy_python-0.1.11.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "31830e9a0c7de4f36a75cadc9532c38a", "sha256": "0697a28c9985506c31980c7dbaa2337c86d2d9427fb993453f7ca7d5274b7fb9" }, "downloads": -1, "filename": "lazy_python-0.1.2.tar.gz", "has_sig": false, "md5_digest": "31830e9a0c7de4f36a75cadc9532c38a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12378, "upload_time": "2015-02-21T02:00:03", "url": "https://files.pythonhosted.org/packages/c4/1a/27a0c3bdafe049b66c9a285289b09041208fcd51d997e7d0db2b234ed7ff/lazy_python-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "1b0ce7e59e780939c6d4259931147ccb", "sha256": "3c1c7b94f909f18c51d4baf78c1281ec3e554fd250c63ea97a10651ea403d53b" }, "downloads": -1, "filename": "lazy_python-0.1.3.tar.gz", "has_sig": false, "md5_digest": "1b0ce7e59e780939c6d4259931147ccb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12788, "upload_time": "2015-02-24T04:26:28", "url": "https://files.pythonhosted.org/packages/34/b9/22e15e155fd98005cd5470f89e074f0ae3656c871a82fc9b778daff37334/lazy_python-0.1.3.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "1744821185f9a6a9a2581544ebe8a352", "sha256": "8f719f7a6d757a0ea1b54cb9d6106b489e37840717dde3ed1bddec7221061d5f" }, "downloads": -1, "filename": "lazy_python-0.1.4.tar.gz", "has_sig": false, "md5_digest": "1744821185f9a6a9a2581544ebe8a352", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13367, "upload_time": "2015-02-24T05:41:50", "url": "https://files.pythonhosted.org/packages/26/2d/1510c01ab427bd2ee30081ddf48886ecc3db3fb923f2c2126d5164bdd303/lazy_python-0.1.4.tar.gz" } ], "0.1.5": [ { "comment_text": "", "digests": { "md5": "577a9d29aea659dafebc79342a719541", "sha256": "fb19d8aff3a930969d49269b5bcbd0c67f06c913b1185e791d1ed0a3c5d5387f" }, "downloads": -1, "filename": "lazy_python-0.1.5.tar.gz", "has_sig": false, "md5_digest": "577a9d29aea659dafebc79342a719541", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13322, "upload_time": "2015-02-24T06:37:38", "url": "https://files.pythonhosted.org/packages/4a/a4/8ce231ce0f7eaf9330a896c544cb693723ae92d6a85f4e7802a1d4a7b185/lazy_python-0.1.5.tar.gz" } ], "0.1.6": [ { "comment_text": "", "digests": { "md5": "116e9fcf55c1d3feb22732a6897c5969", "sha256": "d216a6619bb1a01db40ebd214d2704f12a99608451d97afe30a10e1955529f3d" }, "downloads": -1, "filename": "lazy_python-0.1.6.tar.gz", "has_sig": false, "md5_digest": "116e9fcf55c1d3feb22732a6897c5969", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13639, "upload_time": "2015-02-25T04:05:05", "url": "https://files.pythonhosted.org/packages/dd/31/0e40fff413a8667bac70f037eb310b3895a7984841c8ca7c05d0a911f6da/lazy_python-0.1.6.tar.gz" } ], "0.1.6.0": [ { "comment_text": "", "digests": { "md5": "c9741d0f6a9244e49d3239514090bb65", "sha256": "348b42ef0ce9da9bdd2f21dce1b3b2bddbc11ccb3bdf47b531e755ea5f3e5854" }, "downloads": -1, "filename": "lazy_python-0.1.6.0.tar.gz", "has_sig": false, "md5_digest": "c9741d0f6a9244e49d3239514090bb65", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13652, "upload_time": "2015-02-25T04:09:37", "url": "https://files.pythonhosted.org/packages/ba/5a/9bfa047bcb1993a27535a4c20503d8b6ffe615a713cb3d1309baeb1e182e/lazy_python-0.1.6.0.tar.gz" } ], "0.1.7": [ { "comment_text": "", "digests": { "md5": "117af69f082ae8009f6252b64763a2a3", "sha256": "36b2bbdb438ed11a87fb421a3f9ffef23c9b5e89dc8ceb4ccf075027a1812575" }, "downloads": -1, "filename": "lazy_python-0.1.7.tar.gz", "has_sig": false, "md5_digest": "117af69f082ae8009f6252b64763a2a3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14440, "upload_time": "2015-02-25T06:25:37", "url": "https://files.pythonhosted.org/packages/8c/39/e5f99367bc351386829fb2add3bd8574f19981c79d627d6c4adff1fa76ef/lazy_python-0.1.7.tar.gz" } ], "0.1.8": [ { "comment_text": "", "digests": { "md5": "5f3d58f83aa7c8b1f27d8e2bd6d10cd6", "sha256": "394b5335ae36ff9f6544ec5ef2ff6efa595efdedf4b03da83d4730f98a4bb42c" }, "downloads": -1, "filename": "lazy_python-0.1.8.tar.gz", "has_sig": false, "md5_digest": "5f3d58f83aa7c8b1f27d8e2bd6d10cd6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13362, "upload_time": "2015-03-02T05:42:49", "url": "https://files.pythonhosted.org/packages/38/0d/d79b161b123dd16302e2d04d77b15c060b8d199bbc4a8895c205835ae081/lazy_python-0.1.8.tar.gz" } ], "0.1.9": [ { "comment_text": "", "digests": { "md5": "2319ea15019d9a27d789703a036621b3", "sha256": "9a3b934ba3ef0fb8c6b60656864d4a4cfbb6f5b7aa289f84f3d833b81df09753" }, "downloads": -1, "filename": "lazy_python-0.1.9.tar.gz", "has_sig": false, "md5_digest": "2319ea15019d9a27d789703a036621b3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18816, "upload_time": "2015-04-17T02:39:51", "url": "https://files.pythonhosted.org/packages/35/0e/ba536c159b0603566d92ac38261b7fab07f7149e52f75c7bbcd602241ecb/lazy_python-0.1.9.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "db370bd78a06322363f7d3c09c8a6bdb", "sha256": "908581b101a908343017b961314a519d6a44ef9184f5f1fc52de73b525060bea" }, "downloads": -1, "filename": "lazy_python-0.2.0.tar.gz", "has_sig": false, "md5_digest": "db370bd78a06322363f7d3c09c8a6bdb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18951, "upload_time": "2016-07-21T03:13:50", "url": "https://files.pythonhosted.org/packages/0b/00/25353939da9474d0169dc897a009111f6b3e80b74fa49934e1372ec5d8a2/lazy_python-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "2c95c0d40671746851ce96c7c4aaaf84", "sha256": "5fc4c838ff1654d823f777fef96f1a69084a286431391552d6b849c3bac2c61e" }, "downloads": -1, "filename": "lazy_python-0.2.1.tar.gz", "has_sig": false, "md5_digest": "2c95c0d40671746851ce96c7c4aaaf84", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24140, "upload_time": "2016-07-21T03:31:55", "url": "https://files.pythonhosted.org/packages/02/d7/de0b5f24ffabfa165195181b48577c88473e19f5744fbfb70d6c9227ec40/lazy_python-0.2.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "2c95c0d40671746851ce96c7c4aaaf84", "sha256": "5fc4c838ff1654d823f777fef96f1a69084a286431391552d6b849c3bac2c61e" }, "downloads": -1, "filename": "lazy_python-0.2.1.tar.gz", "has_sig": false, "md5_digest": "2c95c0d40671746851ce96c7c4aaaf84", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24140, "upload_time": "2016-07-21T03:31:55", "url": "https://files.pythonhosted.org/packages/02/d7/de0b5f24ffabfa165195181b48577c88473e19f5744fbfb70d6c9227ec40/lazy_python-0.2.1.tar.gz" } ] }