Black Magic - Currying using __get__

Discussion in 'Python' started by Michael Spencer, Mar 24, 2005.

  1. Wow - Alex Martelli's 'Black Magic' Pycon notes
    http://www.python.org/pycon/2005/papers/36/pyc05_bla_dp.pdf

    include this gem:
    > Functions 'r descriptors
    > def adder(x, y): return x + y
    > add23 = adder.__get__(23)
    > add42 = adder.__get__(42)
    > print add23(100), add42(1000)
    > 123 1042


    This means that you can do (left) currying without a separate curry function
    (Of course, google reveals that the idea has been discussed before,
    http://mail.python.org/pipermail/python-dev/2003-October/038933.html)


    Although it's less flexible than a general curry function, 'method currying' is
    much faster, e.g., compare two functions for tail-filtering an iterator:

    def filtertail(op, iterable):
    """Recursively filter the tail of an iterator, based on its head
    Useful for succinct (though not very fast) implementations
    of sieve of eratosthenes among other"""
    iterator = iter(iterable)
    while 1:
    head = iterator.next()
    yield head
    iterator = it.ifilter(curry(op,Missing,head), iterator)

    def filtertail2(op, iterable):
    """An alternative to filtertail, using Alex Martelli's observation
    that functions are descriptors. Will not work for built-in
    functions that lack a __get__ method"""
    iterator = iter(iterable)
    opcurry = op.__get__
    while 1:
    head = iterator.next()
    yield head
    iterator = it.ifilter(opcurry(head), iterator)

    using these generator functions, a Sieve of Eratosthenes can be written as:

    primes = list(filtertail(operator.mod, xrange(2,N)))
    or
    primes = list(filtertail2(lambda head, tail: tail % head, xrange(2,N)))

    but the second version, using 'method currying' is 4 times the speed, despite
    not using the stdlib operator.mod function

    def timethem(N):
    import time
    t1 = time.clock()
    p = list(filtertail(op.mod, xrange(2,N)))
    t2 = time.clock()
    p = list(filtertail2(lambda head, tail: tail % head, xrange(2,N)))
    t3 = time.clock()
    return t2-t1, t3-t2

    >>> timethem(10000)

    (3.8331997502475588, 0.79605759949936328)
    >>> timethem(100000)

    (240.68151008019186, 61.818026872130304)
    >>>


    of course, neither version is anywhere near the most efficient Python
    implementation - this is a comparison of currying, not sieving.


    BTW, here's the curry function I used (it could probably be faster; I'm not sure
    what/where the future stdlib version is)


    Missing = Ellipsis
    def curry(*cargs, **ckwargs):
    fn, cargs = cargs[0], cargs[1:]
    if cargs[0] is Missing:
    while cargs[0] is Missing: # rightcurry
    cargs = cargs[1:]
    def call_fn(*fargs, **fkwargs):
    d = ckwargs.copy()
    d.update(fkwargs)
    return fn(*(fargs+cargs),**d)
    name = "%s(...,%s)" % (fn.__name__, ",".join(repr(i) for i in cargs))
    else:
    def call_fn(*fargs, **fkwargs):
    d = ckwargs.copy()
    d.update(fkwargs)
    return fn(*(cargs + fargs), **d)
    name = "%s(%s,...)" % (fn.__name__, ",".join(repr(i) for i in cargs))
    call_fn.func_name = name
    call_fn.curry = True
    return call_fn

    Michael
    Michael Spencer, Mar 24, 2005
    #1
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Shalabh Chaturvedi
    Replies:
    2
    Views:
    443
    Mike C. Fletcher
    Feb 20, 2004
  2. Jan Burgy
    Replies:
    2
    Views:
    602
    Jan Burgy
    Aug 16, 2004
  3. Andrew Robert

    regex/lambda black magic

    Andrew Robert, May 25, 2006, in forum: Python
    Replies:
    5
    Views:
    400
    John Machin
    May 25, 2006
  4. fdm
    Replies:
    18
    Views:
    696
    Balog Pal
    Oct 5, 2009
  5. Tom Willis

    Ruby black magic? Meta Programming

    Tom Willis, Mar 12, 2005, in forum: Ruby
    Replies:
    4
    Views:
    318
    Mathieu Bouchard
    Mar 13, 2005
Loading...

Share This Page