[Tutor] Which is better style for a function that modifies a list?

dn PyTutor at DancesWithMice.info
Wed Jun 23 23:02:45 EDT 2021


On 24/06/2021 12.31, boB Stepp wrote:
> On Wed, Jun 23, 2021 at 6:58 PM boB Stepp <robertvstepp at gmail.com> wrote:
>>
>> I am tremendously enjoying "Practical Programming -- An Introduction
>> to Computer Science Using Python 3.6, 3rd Edition" by Paul Gries,
>> Jennifer Campbell and Jason Montojo, c. 2017.  I highly recommend it
>> to anyone who needs to learn fundamental Python and/or introductory
>> computer science.
>>
>> In its chapter on lists the authors point out that a function like
>>
>> def remove_last_item(L: list) -> list:
>>     """Return list L with the last item removed."""
>>
>>     del L[-1]
>>     return L
>>
>> does not require the return statement since the original passed in
>> list will be modified in place, so there is no need for the function
>> to return anything.  I know from experience reading the Tutor and main
>> lists that this is a frequent "gotcha" that catches many fellow
>> learners.  So I wonder:
>>
>> 1)  For such a function that mutates the passed-in list is it
>> clearer/better style to keep or omit the return statement?  Which
>> reads better?
> 
> In light of an earlier thread I started plus now examining all of the
> list methods I conclude that the Pythonic way must be to omit the
> "return" statement, so that "None" is returned (Or return "None"
> explicitly.) whenever a list is modified in place without returning a
> new list.


+1, why add an unnecessary LoC?

Unless... the intent is to return an entirely new list.

Except... Zen of Python says "explicit > implicit".

???


I'm concerned that the function offers little, um, functionality. In
short, would it not be better to write:

del original_list[ -1 ]

rather than:

remove_last_item( original_list )

Well... (to part-answer my own question), isn't the latter more readable?


Is part of this prevarication and 'hedging my bets' due to the lack of
functionality? In other words, if someone came-up with a more realistic
example, might one 'side' of the argument fall-away?


There is a branch of programming-thought called "Functional Programming"
and one of the aspects of code it seeks to avoid is "side-effects". The
'gotcha' implicit within mutable collections has been discussed in an
earlier thread. If we want to remove_/del is it really a side-effect?


Perhaps if we were considering the wider objective(s), and thereafter
why we are removing the list's (or string's, or ...) last element, ie
what other functionality we will be asking of the 'list', our thinking
may lead us to create a custom class/object, sub-classed from list (or ...)?

Whilst this seems an OTT solution to the bare-scenario painted above,
assuming other justification, a custom class would enable:

particular_purpose_list = CustomClass( etc )
...
particular_purpose_list.remove_last_item()

Because the internal "state" of our object-instance is maintained within
"self", there is now little doubt of what is happening, and to what.
There is no 'gotcha' (assuming good practice code). Plus, it elevates
the suspicion of a side-effect to being a desired-impact. All of which
results in the code/data-structure being more tightly testable because
it implements a more bounded purpose.


Your thoughts?
--
Regards,
=dn


More information about the Tutor mailing list