Given the following example code:
def myfunc(item):
if item == 2:
item = 1
mylist = [1,2,3]
for i in mylist:
myfunc(i)
print(mylist) # output is [1, 2, 3]
# desired output is [1, 1, 3]
I would like to have a function that is called for some or all elements of a list. This function should be able to alter these elements.
What would be the the cleanest solution for this problem?
As you’ve written
myfunc, working on individual items, it cannot modify the list in place. This is a good thing.myfuncreceives the nameitembound to some value. You can rebind the nameitemto a new value, but that of course doesn’t affect any other bindings to the same value. All a list is is an ordered sequence of bindings to values, so to change what it contains you have to rebind some of the indexes in the list to new values (or change the values themselves, but numbers can’t be changed; there’s no way to change the number 1 into the number 2, you can only rebind something that referred to the number 1 to refer to the number 2 instead). With no reference to the list, there’s no way formyfuncto change the bindings in the list.But
myfuncshouldn’t have to care about the list. It works on items, and it doesn’t care whether you got those items from a list, or a dictionary, or read them from a file, or whatever. This is what I said is a good thing aboutmyfuncnot being able to modify your list; otherwise you’d have to rewritemyfuncfor every different context your items might appear in.Instead, just have
myfuncreturn the new value:Now the code that calls
myfunccan do what you want. This code is aware that the items are being fetched from a list, and that you’re trying to transform the list in place by replacing each item with whatevermyfuncdoes to it. So this is the place you should implement that intention; trying to push it down intomyfuncis not the way to keep complexity away frommyfunc.If you find you’re repeating this pattern all the time for lots of different functions, you can abstract that out into another function:
Now you’ve defined the transformation logic once, and each different item transformation once (and you can re-use the item transformation functions in other contexts than list transformations), and for any given place where you want to transform the items in a list in-place through a function all you have to do is call
inplace_map, which very clearly states what you’re doing.