How to apply function to elements of a list without creating a new list?
Question:
I want to apply a function to all elements in the list, but I want to actually change the elements (which are objects), not view results. I think this is the problem with using map()
or list comprehensions.
class Thing(object):
pass
# some collection of things
my_things
# they are all big...
# produces SyntaxError: invalid syntax
[i.size = "big" for i in my_things]
# produces SyntaxError: lambda cannot contain assignment
map(lambda i: i.size="big", [i for i in my_things])
# no error, but is it the preferred way?
for i in my_things:
i.size="big"
What is the way to do this?
Answers:
I think this is the problem with using map() or list comprehensions.
Not entirely.
my_things[:] = map(...)
And what’s wrong with
for i in my_things:
i.size = "big"
You don’t want to use neither map
nor list comprehansion because they actually create new lists. And you don’t need that overhead, do you?
You could use the __setattr__
method to assign the attribute in a list comprehension. Although, according to some SO threads, using list comprehensions without using the output is not pythonic.
[i.__setattr__('size', 'big') for i in my_things]
While I agree that there is nothing wrong with
for i in my_things:
i.size = "big"
some people are hot into python one-liners. 😉
One option is to add a set method to your class, which can then be called from lambda (essentially hiding the assignment in a function):
class Thing(object):
def setSize(self, size):
self.size = size
map(lambda i: i.setSize("big"), my_things)
maybe like this on python3:
[dict(**i.__dict__, size='big') for i in my_things]
or
map(lambda x: dict(**x.__dict__, size='big'), my_things)
if i is dict not object
[dict(**i, size='big') for i in my_things]
on python2
[dict(i.copy(), size='big') for i in my_things] # isinstance(i, dict)
[dict(i.__dict__.copy(), size='big') for i in my_things] # isinstance(i, object)
I want to apply a function to all elements in the list, but I want to actually change the elements (which are objects), not view results. I think this is the problem with using map()
or list comprehensions.
class Thing(object):
pass
# some collection of things
my_things
# they are all big...
# produces SyntaxError: invalid syntax
[i.size = "big" for i in my_things]
# produces SyntaxError: lambda cannot contain assignment
map(lambda i: i.size="big", [i for i in my_things])
# no error, but is it the preferred way?
for i in my_things:
i.size="big"
What is the way to do this?
I think this is the problem with using map() or list comprehensions.
Not entirely.
my_things[:] = map(...)
And what’s wrong with
for i in my_things:
i.size = "big"
You don’t want to use neither map
nor list comprehansion because they actually create new lists. And you don’t need that overhead, do you?
You could use the __setattr__
method to assign the attribute in a list comprehension. Although, according to some SO threads, using list comprehensions without using the output is not pythonic.
[i.__setattr__('size', 'big') for i in my_things]
While I agree that there is nothing wrong with
for i in my_things:
i.size = "big"
some people are hot into python one-liners. 😉
One option is to add a set method to your class, which can then be called from lambda (essentially hiding the assignment in a function):
class Thing(object):
def setSize(self, size):
self.size = size
map(lambda i: i.setSize("big"), my_things)
maybe like this on python3:
[dict(**i.__dict__, size='big') for i in my_things]
or
map(lambda x: dict(**x.__dict__, size='big'), my_things)
if i is dict not object
[dict(**i, size='big') for i in my_things]
on python2
[dict(i.copy(), size='big') for i in my_things] # isinstance(i, dict)
[dict(i.__dict__.copy(), size='big') for i in my_things] # isinstance(i, object)