The Python Toolbox Documentation

Contents:

Topical guides to the Python Toolbox

(This section is still incomplete.)

These are topical guides about the various modules in the Python Toolbox.

It focuses on giving the motivation for each module in the Python Toolbox, explaining what it’s good for and the basics of using it.

abc_tools - documentation not written

address_tools - documentation not written

arguments_profile - documentation not written

binary_search - documentation not written

caching

The caching modules provides tools related to caching:

caching.cache()

A caching decorator that understands arguments

The idea of a caching decorator is very cool. You decorate your function with a caching decorator:

>>> from python_toolbox import caching
>>>
>>> @caching.cache
... def f(x):
...     print('Calculating...')
...     return x ** x # Some long expensive computation

And then, every time you call it, it’ll cache the results for next time:

>>> f(4)
Calculating...
256
>>> f(5)
Calculating...
3125
>>> f(5)
3125
>>> f(5)
3125

As you can see, after the first time we calculate f(5) the result gets saved to a cache and every time we’ll call f(5) Python will return the result from the cache instead of calculating it again. This prevents making redundant performance-expensive calculations.

Now, depending on the function, there can be many different ways to make the same call. For example, if you have a function defined like this:

def g(a, b=2, **kwargs):
    return whatever

Then g(1), g(1, 2), g(b=2, a=1) and even g(1, 2, **{}) are all equivalent. They give the exact same arguments, just in different ways. Most caching decorators out there don’t understand that. If you call g(1) and then g(1, 2), they will calculate the function again, because they don’t understand that it’s exactly the same call and they could use the cached result.

Enter caching.cache():

>>> @caching.cache()
... def g(a, b=2, **kwargs):
...     print('Calculating')
...     return (a, b, kwargs)
...
>>> g(1)
Calculating
(1, 2, {})
>>> g(1, 2) # Look ma, no calculating:
(1, 2, {})
>>> g(b=2, a=1) # No calculating again:
(1, 2, {})
>>> g(1, 2, **{}) # No calculating here either:
(1, 2, {})
>>> g('something_else') # Now calculating for different arguments:
Calculating
('something_else', 2, {})

As you can see above, caching.cache() analyzes the function and understands that calls like g(1) and g(1, 2) are identical and therefore should be cached together.

Both limited and unlimited cache

By default, the cache size will be unlimited. If you want to limit the cache size, pass in the max_size argument:

>>> @caching.cache(max_size=7)
... def f(): pass

If and when the cache size reaches the limit (7 in this case), old values will get thrown away according to a LRU order.

Sleekrefs

caching.cache() arguments with sleekrefs. Sleekrefs are a more robust variation of weakrefs. They are basically a gracefully-degrading version of weakrefs, so you can use them on un-weakreff-able objects like int, and they will just use regular references.

The usage of sleekrefs prevents memory leaks when using potentially-heavy arguments.

caching.CachedType

A class that automatically caches its instances

Sometimes you define classes whose instances hold absolutely no state on them, and are completey determined by the arguments passed to them. In these cases using caching.CachedType as a metaclass would cache class instances, preventing more than one of them from being created:

>>> from python_toolbox import caching
>>>
>>> class A(object):
...      __metaclass__ = caching.CachedType
...      def __init__(self, a=1, b=2):
...          self.a = a
...          self.b = b

Now every time you create an instance, it’ll be cached:

>>> my_instance = A(b=3)

And the next time you’ll create an instance with the same arguments:

>>> another_instance = A(b=3)

No instance will be actually created; the same instance from before will be used:

>>> assert another_instance is my_instance

caching.CachedProperty

A cached property

Oftentimes you have a property on a class that never gets changed and needs to be calculated only once. This is a good situation to use caching.CachedProperty in order to have that property be calculated only one time per instance. Any future accesses to the property will use the cached value.

Example:

>>> import time
>>> from python_toolbox import caching
>>>
>>> class MyObject(object):
...     # ... Regular definitions here
...     def _get_personality(self):
...         print('Calculating personality...')
...         time.sleep(5) # Time consuming process...
...         return 'Nice person'
...     personality = caching.CachedProperty(_get_personality)

Now we create an object and calculate its “personality”:

>>> my_object = MyObject()
>>> my_object.personality
'Nice person'
>>> # We had to wait 5 seconds for the calculation!

Consecutive calls will be instantaneous:

>>> my_object.personality
'Nice person'
>>> # That one was cached and therefore instantaneous!

change_tracker - documentation not written

cheat_hashing - documentation not written

color_tools - documentation not written

comparison_tools - documentation not written

context_managers - documentation not written

copy_mode - documentation not written

copy_tools - documentation not written

cute_inspect - documentation not written

cute_iter_tools - documentation not written

cute_profile - documentation not written

cute_testing - documentation not written

decorator_tools - documentation not written

dict_tools - documentation not written

emitters - documentation not written

exceptions - documentation not written

freezers - documentation not written

function_anchoring_type - documentation not written

gc_tools - documentation not written

identities - documentation not written

import_tools - documentation not written

infinity - documentation not written

introspection_tools - documentation not written

logic_tools - documentation not written

math_tools - documentation not written

misc_tools - documentation not written

module_tasting - documentation not written

monkeypatch_copy_reg - documentation not written

monkeypatching_tools - documentation not written

nifty_collections - documentation not written

os_tools - documentation not written

package_finder - documentation not written

path_tools - documentation not written

persistent - documentation not written

pickle_tools - documentation not written

process_priority - documentation not written

proxy_property - documentation not written

queue_tools - documentation not written

random_tools - documentation not written

re_tools - documentation not written

read_write_lock - documentation not written

reasoned_bool - documentation not written

rst_tools - documentation not written

sequence_tools - documentation not written

sleek_refs - documentation not written

string_cataloging - documentation not written

string_tools - documentation not written

sys_tools - documentation not written

temp_file_tools - documentation not written

temp_value_setters - documentation not written

third_party - documentation not written

tracing_tools - documentation not written

version_info - documentation not written

wx_tools - documentation not written

zip_tools - documentation not written

Miscellaneous topics

Mailing Lists

There are three Python Toolbox groups, a.k.a. mailing lists:

This documentation is still incomplete. If you have any questions or feedback, say hello on the mailing list!


The Python Toolbox repository is at: https://github.com/cool-RR/python_toolbox

Feel free to fork and send pull requests!

Table Of Contents