from __future__ import print_function
import os
import sys
import functools
import contextlib
import hashlib
import numpy
import fcntl

def make_list(generator_func):
    """Create a list from a generator function.
    """
    def wrapper(*args, **kwargs):
        return list(generator_func(*args, **kwargs))
    return functools.update_wrapper(wrapper, generator_func)

def vectorize(generator_func):
    """Create a numpy array from an generator function.
    
    numpy.fromiter could have been used, but then the dtype would
    have to be specified (or maybe guessed based on the first item).
    This version is not super efficient, but easy to use.

    >>> @vectorize
    ... def func():
    ...     yield 1
    ...     yield 2
    ...     yield 3.4
    >>> func()
    array([ 1. ,  2. ,  3.4])
    """
    def wrapper(*args, **kwargs):
        return numpy.array(list(generator_func(*args, **kwargs)))
    return functools.update_wrapper(wrapper, generator_func)

@contextlib.contextmanager
def flocked(file, exclusive=True):
    fcntl.flock(file, fcntl.LOCK_EX if exclusive else fcntl.LOCK_SH)
    try:
        yield
    finally:
        fcntl.flock(file, fcntl.LOCK_UN)

@contextlib.contextmanager
def capture_stdout(file=None):
    """Capture output temporarily.

    Use as:
    >>> import io
    >>> with capture_stdout(io.StringIO()) as c:
    ...    print(u'hello, world')
    >>> print(c.getvalue(), end='')
    hello, world

    Or simply as:
    >>> def invoke_crazy_function_which_spews_garbage_on_stdout():
    ...    print('x' * 1000)
    >>> with capture_stdout():
    ...    invoke_crazy_function_which_spews_garbage_on_stdout()
    """
    stdout = sys.stdout
    if file is None:
        file = open(os.devnull, 'w')
    sys.stdout = file
    try:
        yield file
    finally:
        sys.stdout = stdout

@contextlib.contextmanager
def chdired(dirname):
    """Change directory temporarily"""
    old = os.getcwd()
    os.chdir(dirname)
    try:
        yield
    finally:
        os.chdir(old)

@contextlib.contextmanager
def numpy_seterr(all=None, divide=None, over=None, under=None, invalid=None):
    old = numpy.seterr(all=all, divide=divide, over=over, under=under,
                       invalid=invalid)
    try:
        yield
    finally:
        numpy.seterr(**old)

def disk_cached(basepath):
    """
    Caches results in numpy files on disk.

    Specified basepath must be under the control of the caller,
    and entries must be cleaned manually. So this a basis for
    a solution, not the final thing certainly.

    >>> @disk_cached('/tmp/f_result_')
    ... def f(*args, **kwargs):
    ...     print('f')
    ...     ans = numpy.array([len(args), len(kwargs)])
    ...     return ans
    >>> f(3)
    f
    array([1, 0])
    >>> f(3)
    array([1, 0])
    >>> f(*[3])
    array([1, 0])
    >>> f(a=1, b=2)
    f
    array([0, 2])
    >>> f(b=2, a=1)
    array([0, 2])
    >>> f([1,2,3])
    f
    array([1, 0])
    >>> f([1,2,3])
    array([1, 0])
    """
    def decorator(func):
        def wrapper(*args, **kwargs):
            key = (args, tuple(sorted(kwargs.items())))
            tag = hashlib.sha1(repr(key)).hexdigest()
            path = basepath + tag + '.npy'
            try:
                ans = numpy.load(path)
            except TypeError:
                print('warning: function arguments are unhashable')
                return func(*args, **kwargs)
            except IOError:
                # value is not present in cache
                ans = func(*args, **kwargs)
                numpy.save(path, ans)
            return ans
        return functools.update_wrapper(wrapper, func)
    return decorator
 
advanced_python/additional_examples.txt · Last modified: 2012/09/10 11:11 by zbyszek
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki