{ "info": { "author": "Georg Bauer", "author_email": "gb@rfc1437.de", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python" ], "description": "-*- restructuredtext -*-\n\nLazy Evaluation for Python\n============================\n\nThis package implements something like lazy evaluation for Python - and\nit does so in 100% Python code. Installation is standard:\n\neasy_install lazypy\n\nI test and work with it under Python 2.6, so that's where I can say it\nworks with newer versions. For older versions you lose forked futures,\nsince multiprocessing is part of Python starting with 2.6. But it might\nbe possible to still make it work with versions as far back as Python 2.3.\n\nATTENTION: if you used versions before 0.5, you had a different module name\n`LazyEvaluation` instead of of the current `lazypy`. I changed this with 0.5\nbut kept the `LazyEvaluation` package name around as a proxy for old code.\nThis old package name is deprecated, though, and will go away in one of the\nfuture versions. One breaking change is that `__version__` is only available\nthrough the `lazypy` package, not the old compatibility package.\n\nWhat is lazy evaluation or promises?\n--------------------------------------\n\nLazy evaluation is a way to encapsulate a calculation without actually\ncomputing it - it will only be computed when the result of that calculation\nis actually accessed. After the calculation is done, further access to\nthe lazy calculation will just return the cached result.\n\nOf course, since Python doesn't support lazy evaluation natively and since\nthere aren't enough hooks in the interpreter to do something like this\nin Python at all, this is faked lazy evaluation. What it actually does, is\nwrapping function calls in objects that will force the function call result\nat the latest possible moment.\n\nRegardless of what happens, a Promise should produce the same error message\nyou would get without the Promise - just the code location should be\ndifferent. This should be the case - but I can't guarantee it yet. If you\nnotice a situation where a Promise gives some different exception from the\nobject itself in the same situation, please notify me.\n\nThere are several ways to get lazy evaluation in your code. The primary way\nis to use either the lazy/delay functions or to subclass LazyEvaluated or\nto use the LazyEvaluationMetaClass as a metaclass to your own class.\n\nUsing delay\n-----------------\n\n>>> from LazyEvaluation import delay\n>>> \n>>> def func(a, b):\n... return a+b\n...\n>>> res = delay(func, (5, 6))\n>>> \n>>> print repr(res)\n>>> print res\n\nThis will print out a Promise instance in the first print statement and a\nnumber in the second print statement. This happens because print calls the\n__str__ method on objects passed in (or actually it uses the str builtin or\nsomething much like that one - on some objects it will call __str__ and on\nothers like strings it will just return the string itself).\n\nUsing lazy\n------------\n\n>>> from LazyEvaluation import lazy\n>>>\n>>> def func(a, b):\n... return a+b\n...\n>>> func = lazy(func)\n>>> print repr(func(5,6))\n>>> print func(5,6)\n\nThis will print the Promise instance in the first print and the number 11\nin the second print. The function 'lazy' turns any function into it's lazy\nequivalent. It can be used as decorator in Python 2.4 and up.\n\nUsing LazyEvaluated\n--------------------\n\n>>> from LazyEvaluation import LazyEvaluated\n>>>\n>>> class TestClass(LazyEvaluated):\n...\n... def test(self, a, b):\n... return a+b\n...\n>>> print repr(TestClass().test(5,6))\n>>> print TestClass().test(5,6)\n\nThis will print the result number. To use LazyEvaluated will turn your class\ninto a lazy evaluated class. Only the direct attributes will be turned into\nlazy evaluated methods, though! It's just a handy way if you don't have\na full class hierarchy but just a single class you want to turn into something\nthat evaluates lazy. It's probably not the best way to do this.\n\nUsing LazyEvaluatedMetaClass\n------------------------------\n\n>>> from LazyEvaluation import LazyEvaluatedMetaClass\n>>>\n>>> class TestClass(object):\n...\n... __metaclass__ = LazyEvaluatedMetaClass\n...\n... def test(self, a, b):\n... return a+b\n...\n>>> print repr(TestClass().test(5,6))\n>>> print TestClass().test(5,6)\n\nThis will make all function attributes of your class into lazy evaluated\nmethods. It's mostly identical to the above sample, only that it doesn't\nuse inheritance. It might be usefull to build subclasses to already existing\nclasses whose direct function attributes are evaluated lazy.\n\nSome bits on the semantics\n----------------------------\n\nLazy evaluation for Python behaves a bit different from what fully lazy\nlanguages behave: it's not really full lazy evaluation but just deferred\nevaluation. Results are forced to be evaluated at the latest possible moment.\nTo achieve this, the Promise class implements many standard magic methods\nand implement them by first forcing the deferred evaluations (so getting\ntheir real value) and applying the builtin method to those values.\n\nIt has special handling for binary operator methods in that it first tries\nthe primary method that was called and if that either doesn't exist or\nreturns NotImplemented it will run the other method with reversed arguments.\nThis should work for most situations where binary operators are used.\n\nSometimes you might have the need to force evaluation without using any of\nthe normal ways to force evaluation - for example to store a forced value\nsomewhere. You can use the force(value) function for this:\n\n>>> from LazyEvaluation import force\n>>>\n>>> def anton(a,b):\n... return range(a,b)\n...\n>>> f = lazy(anton)\n>>> l = f(1,10)\n>>> l = force(l)\n>>> print l\n\nThere is one speciality in the behaviour of promises that can produce\nproblems in your code: getattr and setattr don't force it's object!\ncalling setattr on the promise actually will setattr to the promise object\nitself, not to the forced value. So if you set an attribute value on a promise\nand later force it, that forced value won't have the originally set attribute.\nThe main reason for this is that overloading __setattr__ in promise classes is\nrather hairy - setattr handles all attribute setting and a promise does have\nsome instance variables (== attributes). If you want to set attributes on\nvalues from a promise, you allways must force the value yourself.\n\nHow to have new behaviour\n---------------------------\n\nSometimes the builtin promise class Promise isn't what you need. If you\nwant to build your own, you have two ways of doing it: either just subclass\nthe Promise class and add your needed stuff or write your own class.\n\nYour own promise class must adhere to the Promise interface. It must\ndefine a __init__ method that accepts a function, an argument list and an\noptional argument dictionary. And it must define a __force__ method that\nforces it's evaluation. And it must use PromiseMetaClass as it's __metaclass__\nas that one will fill in all the needed magic methods. If it needs to change\nthe way some magic method operates, it can just define that method locally -\nthe metaclass will automatically skip that predefined method.\n\nAn example for a different behaviour is the Futures.py module: this implements\nfutures, a high-level-concurrency concept. Instead of just delaying the\ncomputation until the __force__ is called, a thread is started that computes\nthe result in the background. If you try to force a Future, your call will\nblock until the result is ready. Exceptions are catched and later reraised,\ntoo. This allows very easy parallism in your code - just push some\ncomputation into the background and if it is ready when you access it, your\ncode will just go on. Only if it isn't already fullfilled will you have to\nwait for it.\n\nStarting with lazypy 0.3 there are ForkedFutures, too. Those behave much like\nthe normal futures, but run in a separate process. This allows writing code\nthat makes better use of multicore systems, since multiple processes allow\ngetting around the global interpreter lock. These ForkedFutures make use\nof the multiprocessing module in Python 2.6, so won't be available with older\npython versions (and their test cases will fail on older versions).\n\nTo make use of futures, you can just use the spawn/future pair of functions\nthat behave exactly like delay/lazy - spawn is a parallel version of apply\nand future is a decorator that turns any callable into a parallel version\nof itself. To use ForkedFutures, just pass the ForkedFuture class as the\nclass to be used for the future in those calls.\n\nThere is an additional pair of functions fork/forked that use those\nforked futures by default. Remember that they are all just syntactic\nsugar for the same concepts - you can use delay, spawn or fork interchangeably\nby passing the correct target class. Same goes for the decorators.\n\nSo what to use - lazy, future or forked?\n-----------------------------------------\n\nHere is a very simple rundown on the three different variants on promises\nimplemented in lazypy and when to use them:\n\n- delay/lazy is best used when you want to capture a state of computation\n but not run it at the time of capturing, but instead decide later\n when to actually compute it (or wether to not compute it at all). This\n could be some lenghty computation that only will make sense later in\n your code when you discover some special circumstances. You could get\n very similar results with closures, delay and lazy are just more uniform\n idioms for that.\n\n- spawn/future is best used when you have something that can run alongside\n the main thread to compute some lengthy stuff. Since this uses threads\n and since Python has the GIL, this is not really performance enhancing.\n But it can be useful if your main thread mostly waits on stuff and the\n computation can run in parallel to prepare the result that you later\n need.\n\n- fork/forked is best used when you need to make use of multiple cores and\n want some lengthy calculation run alongside the main process to prepare\n a result you will need later. Since full processes are used, you can make\n full use of your multiple cores to speed up some calculations that are\n parallelizable.\n\nIn general, all three promise variants could be replicated by using the\nunderlying mechanisms directly (lazy evaluation can be simulated using\nclosures, futures can be just implemented with the threading or the\nmultiprocessing modules directly). lazypy only gives a nice syntactic\nwrapper around it and a way to add parallelism or lazy evaluation to\ncode that is allready there - without the need of changing the consuming\ncode. It can be especially useful if you work in a functional style\nwith Python or if you want to annotate existing classes to get lazy or\nfuture semantics on some of it's methods.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://bitbucket.org/rfc1437/lazypy/", "keywords": null, "license": "MIT/X", "maintainer": null, "maintainer_email": null, "name": "lazypy", "package_url": "https://pypi.org/project/lazypy/", "platform": "BSD,Linux,MacOS X,win32", "project_url": "https://pypi.org/project/lazypy/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://bitbucket.org/rfc1437/lazypy/" }, "release_url": "https://pypi.org/project/lazypy/0.5/", "requires_dist": null, "requires_python": null, "summary": "Lazy Evaluation for Python", "version": "0.5" }, "last_serial": 794092, "releases": { "0.2": [ { "comment_text": "", "digests": { "md5": "f279dc14bc00fd87318389955181cb21", "sha256": "db4ab85199af65b76265bcdb246fa0acce9338d794a2df035062e38cbf3189d5" }, "downloads": -1, "filename": "lazypy-0.2-py2.6.egg", "has_sig": false, "md5_digest": "f279dc14bc00fd87318389955181cb21", "packagetype": "bdist_egg", "python_version": "2.6", "requires_python": null, "size": 28128, "upload_time": "2010-03-01T01:23:22", "url": "https://files.pythonhosted.org/packages/0a/3e/e202ddbcb22c055b5a15866e37f8839c29564e692fd9882419fe8107186d/lazypy-0.2-py2.6.egg" }, { "comment_text": "", "digests": { "md5": "f3c54521741b7838e393e6b8e9d9c605", "sha256": "81f0cdc3732ae47db5e2f546bfda72e432025dd74a2a4cdd892e234af9f3bac9" }, "downloads": -1, "filename": "lazypy-0.2.tar.gz", "has_sig": false, "md5_digest": "f3c54521741b7838e393e6b8e9d9c605", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11256, "upload_time": "2010-03-01T01:23:21", "url": "https://files.pythonhosted.org/packages/a0/23/1bb02ed0fe1244fd81e6d4726eacaad96c1b41bbe5caec04760afca0ee5f/lazypy-0.2.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "fe50d922b6501948f9a7abe80469b161", "sha256": "e6c29ae4a24b7f1a3690685eaa6fcb94a34fb6fb4934d099047066a73226c974" }, "downloads": -1, "filename": "lazypy-0.3-py2.6.egg", "has_sig": false, "md5_digest": "fe50d922b6501948f9a7abe80469b161", "packagetype": "bdist_egg", "python_version": "2.6", "requires_python": null, "size": 33827, "upload_time": "2010-03-01T18:22:03", "url": "https://files.pythonhosted.org/packages/64/bd/4aa7f1a747b50ce8bdc96529f80909cbf806609c7cad9bee6b51ef27339f/lazypy-0.3-py2.6.egg" }, { "comment_text": "", "digests": { "md5": "587449af4987e52ed00bf3005db80b8e", "sha256": "e5dcd61e9434c6d3a9146f376d05740be74f72fc80f965883e3c648698b26975" }, "downloads": -1, "filename": "lazypy-0.3.tar.gz", "has_sig": false, "md5_digest": "587449af4987e52ed00bf3005db80b8e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13817, "upload_time": "2010-03-01T18:22:02", "url": "https://files.pythonhosted.org/packages/47/e7/ca9b15c6c13b2b223a96190a6db99145447fcdc65059a5cd90344e901895/lazypy-0.3.tar.gz" } ], "0.5": [ { "comment_text": "", "digests": { "md5": "abc4817e7fdffd92f7f19c48ffc311fa", "sha256": "29ab24917a2bf91e02fd680c84cddf7d785c1df4153f50dc3efd9bc1277bbf5e" }, "downloads": -1, "filename": "lazypy-0.5-py2.6.egg", "has_sig": false, "md5_digest": "abc4817e7fdffd92f7f19c48ffc311fa", "packagetype": "bdist_egg", "python_version": "2.6", "requires_python": null, "size": 38974, "upload_time": "2010-03-07T17:26:19", "url": "https://files.pythonhosted.org/packages/71/d2/5b5ef62887e539c5598527a876f8c4b4d23ab51c8545c61e99d7ac1e0a7c/lazypy-0.5-py2.6.egg" }, { "comment_text": "", "digests": { "md5": "1607dc30e0f48e0bdf63031511f19d2c", "sha256": "2349a362a6d5a9446f9e258a0c7278fc1f15b7e75d29cfd6af4295b78d2ee33c" }, "downloads": -1, "filename": "lazypy-0.5.tar.gz", "has_sig": false, "md5_digest": "1607dc30e0f48e0bdf63031511f19d2c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13745, "upload_time": "2010-03-07T17:26:17", "url": "https://files.pythonhosted.org/packages/85/db/7562edbf2bbaeedac55ab81ded543ad0234d4d32e3ac7314b0339b04b2eb/lazypy-0.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "abc4817e7fdffd92f7f19c48ffc311fa", "sha256": "29ab24917a2bf91e02fd680c84cddf7d785c1df4153f50dc3efd9bc1277bbf5e" }, "downloads": -1, "filename": "lazypy-0.5-py2.6.egg", "has_sig": false, "md5_digest": "abc4817e7fdffd92f7f19c48ffc311fa", "packagetype": "bdist_egg", "python_version": "2.6", "requires_python": null, "size": 38974, "upload_time": "2010-03-07T17:26:19", "url": "https://files.pythonhosted.org/packages/71/d2/5b5ef62887e539c5598527a876f8c4b4d23ab51c8545c61e99d7ac1e0a7c/lazypy-0.5-py2.6.egg" }, { "comment_text": "", "digests": { "md5": "1607dc30e0f48e0bdf63031511f19d2c", "sha256": "2349a362a6d5a9446f9e258a0c7278fc1f15b7e75d29cfd6af4295b78d2ee33c" }, "downloads": -1, "filename": "lazypy-0.5.tar.gz", "has_sig": false, "md5_digest": "1607dc30e0f48e0bdf63031511f19d2c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13745, "upload_time": "2010-03-07T17:26:17", "url": "https://files.pythonhosted.org/packages/85/db/7562edbf2bbaeedac55ab81ded543ad0234d4d32e3ac7314b0339b04b2eb/lazypy-0.5.tar.gz" } ] }