Pythonic way to write a function which modifies a list?

2024/9/8 10:38:33

In python function arguments are passed by object reference. This means the simplest code to modify a list will modify the object itself.

a = [1,2,3]def remove_one(b):b.remove(1)remove_one(a)
print(a)

The method remove_one returns nothing. If that was a public method one has to assume it will modify the object and isn't thread safe inside the method.


A second approach would be to structure the code snippet like this:

a = [1,2,3]def remove_one(b):b.remove(1)return(b)print(remove_one(a[:]))

Here the content of a wasn't modified and a new list is returned. This puts a lot of responsibility on the method caller.


Then again list comprehensions, the pythonic approach of modifying list contents always create a new object.

a = [1,2,3]def remove_one(b):b = [num for num in b if b!=1]return(b)print(remove_one(a))

It isn't clear to me if there is a "pythonic" way to do it so I'll make some assumptions to be challenged:

  • It's safer to assume that a function taking a mutable object will modify it's content
  • There is a reason why list comprehensions don't also directly modify the object. I just don't know it
  • The "pythonic" way to write functions that use list comprehensions to modify the mutable argument isn't clear
Answer

TLDR: If you modify an argument, do not return it.


list.sort() sorts the list in place. In order to remind you of that fact, it does not return the sorted list.

Design and History FAQ

It is idiomatic to indicate whether you modify an argument by not returning it. For example, your first case is correct, your second is not:

def remove_one(b):b.remove(1)  # modify, do not return

If you do not modify an argument but create a copy, you must return the copy for the operation to be meaningful:

def one_removed(b):c = b.copy()  # create new object...c.remove(1)return c      # ...and return it

It is common for function/method names to reflect whether they actively modify their argument. Modifying functions tend to use active verbs, whereas non-modifying functions tend to use passive verbs or adjectives.


There is no "pythonic" choice whether to modify the argument or not - operating on the original or a copy are two fundamentally different operations. Both are valid depending on the use-case.

>>> items = [4, 3, 10, 2, 5]
>>> sorted(items)
[2, 3, 4, 5, 10]
>>> items.sort()
>>> items
[2, 3, 4, 5, 10]

In general, mutating an argument is faster in Python, whereas creating a new result is easier to reason about. In specific, comprehensions represent functional programming operations (namely map and filter) -- they are designed not to modify their iterable.


Whether to return an argument due to modification only concerns said argument. For example, list.pop modifies the list and does not return it -- however, it does return the popped element.

https://en.xdnf.cn/q/73025.html

Related Q&A

Trying different functions until one does not throw an exception

I have some functions which try various methods to solve a problem based on a set of input data. If the problem cannot be solved by that method then the function will throw an exception.I need to try t…

Python: Extracting lists from list with module or regular expression

Im trying to extract lists/sublists from one bigger integer-list with Python2.7 by using start- and end-patterns. I would like to do it with a function, but I cant find a library, algorithm or a regula…

Converting hard integral to lambda function with lambdify

I would like to lambdify the function Integral(t**t,(t,0,x)). It works, but my new function, which was returned by lambdify, doesnt return a number but only sympy.integrals.integrals.Integral class. Bu…

python topN max heap, use heapq or self implement?

theres heapq in python, for general usage. i want recording topN(0~20) for 10e7 records.if use heapq, should use - to translate max to min; and recording a min number of bottom, to call heapq.heappushp…

QSortFilterProxyModel returning artificial row

Im using a QSortFilterProxyModel to filter results from a QAbstractListModel. However, Id like to return a first entry which is not present in the original model, that is, its somehow artificial.This i…

@login_required is losing the current specified language

I am using i18n_patterns to internationalize my app and its working except when I click on a link that requires login (a view protected by @login_required decorator), I am being redirected to the login…

Python slow on fetchone, hangs on fetchall

Im writing a script to SELECT query a database and parse through ~33,000 records. Unfortunately Im running into problems at the cursor.fetchone()/cursor.fetchall() phase of things.I first tried iterati…

Pure Python Quadtree Implementation

All,There are a few examples on implementing a quadtree using Python but my question is, does anyone know of a class written in pure python as in a single .py file that I can easily include in my proje…

AttributeError: tuple object has no attribute write

I have a homework assignment for a Python class and am running into an error that I dont understand. Running Python IDLE v3.2.2 on Windows 7.Below is where the problem is happening:#local variables num…

How to catch all exceptions with CherryPy?

I use CherryPy to run a very simple web server. It is intended to process the GET parameters and, if they are correct, do something with them. import cherrypyclass MainServer(object):def index(self, **…