DmitrySemenov
DmitrySemenov

Reputation: 10315

Dynamically set object attribute with map and setattr function

Trying to achieve the following in Python 2.7.8

class X:
    pass

a = X()
b = X()
t={1: {1: a, 2: b}}

map(lambda x: setattr(x, 'test', 'wow'), t[1].values())

that gives: [None, None], while I expect it to set property 'test' on each to 'wow' if I call setattr(a, 'test', 'wow') outside of map() then everything works

Upvotes: 2

Views: 3218

Answers (1)

Joel
Joel

Reputation: 23827

Please look at the bottom of my answer for a better way to do this. Here is the explanation of what's going on in your example (but again, there is a better way).

class X:
    pass

a = X()
b = X()
t={1: {1: a, 2: b}}

map(lambda x: setattr(x, 'test', 'wow'), t[1].values())

a.test   
> wow

It behaves as expected. Just that setattr returns None (all functions that don't explicitly return a value actually return None). So when you map it, it returns None both times, and map returns the list of the things that setattr returned: [None, None]. map has the side effect that it does change the attributes, which is what you're trying to do, but this isn't what map returns. To demonstrate the behavior more clearly:

response = setattr(a, 'test', 'wow2')
print response  
> None
print a.test  
> wow2

Why not do:

for x in t[1].values():
    setattr(x, 'test', 'wow')

instead. It's not at all clear why you need map. Your confusion came from the fact that map returns a list, but what you were trying to do wasn't get the list, but rather do some operation on each object in a list.

Upvotes: 5

Related Questions