Correct Style for Python functions that mutate the argument
The first way:
def change(array):
array.append(4)
change(array)
is the most idiomatic way to do it. Generally, in python, we expect a function to either mutate the arguments, or return something1. The reason for this is because if a function doesn't return anything, then it makes it abundantly clear that the function must have had some side-effect in order to justify it's existence (e.g. mutating the inputs).
On the flip side, if you do things the second way:
def change(array):
array.append(4)
return array
array = change(array)
you're vulnerable to have hard to track down bugs where a mutable object changes all of a sudden when you didn't expect it to -- "But I thought change
made a copy"...
1Technically every function returns something, that _something_
just happens to be None
...
Preferred way of mutating dictionary inside function/method and returning to the caller?
I'd say better to not return
Well look no further than list.sort()
It sorts list in-place, meaning original list changes, and nothing is returned.
The reason for returning None
is so users do not get confused (thinking original list is preserved)
The most important thing is to properly name what you're doing
e.g.
def fill_with_defaults(cfg):
...
And then fill_with_defaults(configuration)
is looking perfectly readable
And as for "explicit", no return value is even better because the reader knows something is changed in-place
meaning he wouldn't consider config2 = fill_with_defaults(configuration)
leading to buggy code (cuz changing one config affects other)
Python changing variables vs arrays in functions?
You have to look at the documentation. Generally: numbers, strings and
tuple
s are immutable.Regarding specific methods, there is a general rule also: if the method returns something then it doesn't modify the argument. Methods that modify the argument return
None
.a += b
is equivalent toa = a + b
ifa
is immutable. Ifa
is mutable then using+=
will mutate the object. Basically+=
is just a method call (to__iadd__
). In the case of immutable objects the method returns a new object and doesn't mutate the original value, for mutable object the object is mutate and it returns itself.
Understanding Python's call-by-object style of passing function arguments
The key difference is that in C-style language, a variable is a box in memory in which you put stuff. In Python, a variable is a name.
Python is neither call-by-reference nor call-by-value. It's something much more sensible! (In fact, I learned Python before I learned the more common languages, so call-by-value and call-by-reference seem very strange to me.)
In Python, there are things and there are names. Lists, integers, strings, and custom objects are all things. x
, y
, and z
are names. Writing
x = []
means "construct a new thing []
and give it the name x
". Writing
x = []
foo = lambda x: x.append(None)
foo(x)
means "construct a new thing []
with name x
, construct a new function (which is another thing) with name foo
, and call foo
on the thing with name x
". Now foo
just appends None
to whatever it received, so this reduces to "append None
to the the empty list". Writing
x = 0
def foo(x):
x += 1
foo(x)
means "construct a new thing 0
with name x
, construct a new function foo
, and call foo
on x
". Inside foo
, the assignment just says "rename x
to 1 plus what it used to be", but that doesn't change the thing 0.
Edit in-place function should return object reference or not?
The convention in Python is that if a function operates in-place, it returns None. You can see this for example in the list methods .sort
and .append
, which modify the lists they are called on but return None.
Note, your first example does not need return
at all.
Related Topics
Regular Expression: Match Start or Whitespace
How to Implement Band-Pass Butterworth Filter with Scipy.Signal.Butter
Minimum Euclidean Distance Between Points in Two Different Numpy Arrays, Not Within
Python Matplotlib Framework Under MACosx
Differencebetween a Pandas Series and a Single-Column Dataframe
How to Remove Leading and Trailing Zeros in a String? Python
Sorting a 2D Numpy Array by Multiple Axes
Matplotlib Figure Facecolor (Background Color)
Does Flask Support Regular Expressions in Its Url Routing
Import CSV with Different Number of Columns Per Row Using Pandas
Get Loop Count Inside a For-Loop
How to Upload a File to Directory in S3 Bucket Using Boto
Why Does @Foo.Setter in Python Not Work for Me
How to Integrate Flask & Scrapy
Take Multiple Lists into Dataframe
Typeerror: Cannot Create a Consistent Method Resolution Order (Mro)
How to Add Static(Html, CSS, Js, etc) Files in Pyinstaller to Create Standalone Exe File
Finding First and Last Index of Some Value in a List in Python