Say I wanted a simple method that takes a list
and modifies it in-place by appending 5
to it. Below are two methods that do this, but ret(l)
returns while no_ret(l)
does not.
def ret(l):
l.append(5)
return l
def no_ret(l):
l.append(5)
Which method is more pythonic? I'm guessing no_ret()
because if the method is for in-place modification, then there is no need to return since we already have a reference to the object being modified.
And how do they compare in terms of time and space efficiency?
ret(l)
is slower since the return statement adds additional overhead.ret()
simply returns a reference (memory address) so no new memory is used.I noticed that Python provides both the in-place non-returning instance method sort()
and non-in-place returning static method sorted()
. However I can't make my in-place methods to be instance methods of default classes like list
.
When evaluating how pythonic some code is we should look to the standard library. Two mutable objects are:
list
with in-place method append
:
mylist = [1,2,3]
mylist.append(5).append(3) # Throws error 'NoneType' object has no attribute 'append'
dict
with in-place method update
:
mydict={}
mydict.update(mydict).update(mydict) # Throws error 'NoneType' object has no attribute 'update'
We can conclude that in-place methods should return None
Performance considerations:
test.py
def ret(l):
l.append(5)
return l
def no_ret(l):
l.append(5)
def test_ret():
l=[]
for i in xrange(100000):
ret(l)
def test_no_ret():
l=[]
for i in xrange(100000):
no_ret(l)
In IPython with %timeit
:
In [3]: %timeit test_ret()
10 loops, best of 3: 163 ms per loop
In [4]: %timeit test_no_ret()
10 loops, best of 3: 161 ms per loop
The not-returning method is not faster than the returning in C-Python.
edit to comment
You can make any method a instance method of a class in python:
class MyObject(object):
def __init__(self):
self.l=[]
def ret(self):
self.l.append(randint(10,15))
return self
IPython:
In [3]: setattr(MyObject,"ret", ret)
In [4]: MyObject().ret()
Out[4]: <test.MyObject at 0x7f6428e8ccd0>
In [5]: MyObject().ret().l
Out[5]: [15]