collecting attributes - what's wrong ? lambda binding ?

Steven D. Majewski (sdm7g@elvis.med.virginia.edu)
Wed, 23 Feb 1994 13:17:57 -0500

When we have a sequence of objects, it is often necessary to form
a sequence of some attribute of those objects.

This first version works fine. It will return a list of the same
length as "seq", composed of "seq[n].attrib" for all n, or else
'None' if there is no attribute of that name.

# we aren't going to try to catch TypeError: attribute-less object:
# we will consider that an actual error.
#

def collect1( seq, attrib ):
res = []
for x in seq:
try:
res.append( getattr( x, attrib ) )
except AttributeError:
res.append( None )
return res

# construct a dummy class and a test sequence:
class Test:
def __init__( self, thing ):
self.me = thing
self.str = str( thing )
self.what = eval( str( thing ))

testSeq = []
for x in range( 1, 10 ):
testSeq.append( Test( x ) )
testSeq.append( Test( `x` ) )

>>> collect1( testSeq, 'me' )
[1, '1', 2, '2', 3, '3', 4, '4', 5, '5', 6, '6', 7, '7', 8, '8', 9, '9']

This shorted, unsafe ( i.e. non-nil returning version ) looks
like it SHOULD work:

def collect2( seq, attrib ):
return map( lambda obj: getattr( obj, attrib ), seq )

- BUT if called from the defined function 'collect2', it gets
a name error on 'attrib' :

>>> collect2( testSeq, 'me' )
Traceback (innermost last):
File "<stdin>", line 1
File "./collect.py", line 16
return map( lambda obj: getattr( obj, attrib ), seq )
File "./collect.py", line 16
return map( lambda obj: getattr( obj, attrib ), seq )
NameError: attrib

- But if the map() is done from the command level, it DOES work:

>>> map( lambda obj: getattr( obj, 'me' ), testSeq )
[1, '1', 2, '2', 3, '3', 4, '4', 5, '5', 6, '6', 7, '7', 8, '8', 9, '9']

[ Am I wrong ? *SHOULDN'T* this work !_? ]

My guess is that this is some strange interaction of lambda with
the local binding in the subroutine. ( Lambda expects global
binding maybe ? )

I have tried several variants of assigning the formal arg to
another local value first, and even trying to pass 'repr(attrib)'
instead, with pretty much the same results.

Any comments ?

- Steve Majewski (804-982-0831) <sdm7g@Virginia.EDU>
- UVA Department of Molecular Physiology and Biological Physics