views:

300

answers:

1

I want to create a lambda function that takes two numpy arrays and sets a slice of the first to the second and returns the newly set numpy array.

Considering you can't assign things in lambda functions is there a way to do something similar to this?

The context of this is that I want to set the centre of a zeros array to another array in a single line, and the only solution I could come up with is to use reduce and lambda functions.

I.e. I'm thinking about the condensation of this (where b is given):

a = numpy.zeros( numpy.array(b.shape) + 2)
a[1:-1,1:-1] = b

Into a single line. Is this possible? This is just an exercise in oneliners. I have the code doing what I want it to do, I'm just wondering about this for the fun of it :).

+2  A: 

This is ugly; you should not use it. But it is oneline lambda as you've asked:

f = lambda b, a=None, s=slice(1,-1): f(b, numpy.zeros(numpy.array(b.shape) + 2))\
                      if a is None else (a.__setitem__([s]*a.ndim, b), a)[1]

What is __setitem__?

obj.__setitem__(index, value) is equivalent to obj[index] = value in this case. Example:

class A:
    def __setitem__(self, index, value):
       print 'index=%s, value=%s' % (index, value)

a = A()
a[1, 2] = 3

It prints:

index=(1, 2), value=3

Why does __setitem__() return None?

There is a general convention in Python that methods such as list.extend(), list.append() that modify an object in-place should return None. There are exceptions e.g., list.pop().

Y Combinator in Python

Here's blog post On writing Python one-liners which shows how write nameless recursive functions using lambdas (the link is suggested by @Peter Hansen).

J.F. Sebastian
hmmm this is definitely leaning towards what I want. Could you give me any information on this "__setitem__" method? I can't seem to find it in the docs.And as far as I can tell "numpy.put" flattens out the array, according to the docs.Thanks!
VolatileStorm
In my mind this: print numpy.zeros( (10,10) ).__setitem__( numpy.s_[1:-1,1:-1] , numpy.arange(64).reshape(8,8) )should print out a 10x10 array with the centre 8x8 being arange(64). however it just prints out "none". This is probably horribly unreadable, haha. Where's the error? Python doesn't mind doing all these steps if I they are in multiple steps. So it's probably my fault somewhere along the line.
VolatileStorm
You might want to add this link to the response: http://blog.sigfpe.com/2008/09/on-writing-python-one-liners.html
Peter Hansen
@VolatileStorm: I've added info about `__setitem__`.
J.F. Sebastian