Extending a list in #Python

>>> a = []
>>> a.extend([2, 1]) # neat
>>> a += [3, 4] # hmm ok
>>> a += (7, 11) # huh?
>>> a[-1:] += [18, 29] # uh oh
>>> a[:] = [*a, 47, 76] # 😦
>>> a
[2, 1, 3, 4, 7, 11, 18, 29, 47, 76]

#pythonoddity

@treyhunner "There should be one– and preferably only one –obvious way to do it." -The Zen of Python

@peterdrake Exactly what I had in mind when sharing that. 😜

Though in this case I'd say there's approximately two obvious ways to do it.

a.extend([2, 1])

And

a += [2, 1]

Which I use depends on what the surrounding code looks like and the whim of the moment. 🤷

@peterdrake @treyhunner And there is: extend. All others are non-obvious.
@treyhunner I've often wondered why .append() and .extend()?
Whither polymorphism?
See also, your recent posting about tuple-unpacking...
@treyhunner Yeah, the implicit conversion of tuples to lists gets me sometimes. I wish I could turn it off.
@kevin @treyhunner It has nothing to do with touples, and it's not conversion - the operator is implemented so that it works with any iterable.

@b11c @kevin

true, but only for lists!

>>> a = [1, 2]
>>> b = (3, 4)
>>> a += b
>>> b += a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate tuple (not "list") to tuple

The list += operator was made consistent with the list extend method.

But other sequences, both mutable and immutable, typically allow only the same type with +=.

I explain it in my Python Oddities talk here: https://youtu.be/nWC73Llo170?t=735

Talk - Trey Hunner: Python Oddities Explained

YouTube
@treyhunner Not all of them are extending a list. At least a couple (can't check right now, but definitely the last one) are creating a new list object.

@b11c believe it or not, all of them, the last one included, actually mutate the original list.

Even += mutates the list. For lists, += is pretty much syntactic sugar for extend.

@treyhunner Yep, you're right. The += is not surprising though, that's exactly what it's meant to do.
@treyhunner The only one that strikes me as properly odd is "a += (7, 11)". The rest beside "a.extend(b)" and "a += b" (which is essentially an alias of the former) are just a bunch of mechanisms for doing other things that happen to be usable for extending lists, if you like doing it awkwardly.

@talideon yup. that's a weird one!

I explain it in my Python Oddities talk here: https://youtu.be/nWC73Llo170?t=735

The short explanation is that the += operator on lists accepts any iterable to make it consistent with the list extend method.

Talk - Trey Hunner: Python Oddities Explained

YouTube
@treyhunner Not knowing python, I expected the line starting with a[:] to behave as "add {list 'a'}, 47, 76 to list 'a'"

@treyhunner
>>> a[:] = [*a, 47, 76] # 😦

IIRC found via StackOverflow about "subdir_list[:] = []", as "os.walk()" https://docs.python.org/3/library/os.html#os.walk lacks a variable to control recursion:

import os, random
parent_dir = '.'
recurse = random.randint( 0, 1 )
print( f'{recurse = } in {parent_dir}' )
for cur_dir, subdir_list, _ in os.walk( parent_dir ):
if subdir_list:
if not recurse:
subdir_list[:] = []
subdir_list.sort()
print( [ f'{cur_dir}/{s}' for s in subdir_list ] )
#Python #wart

os — Miscellaneous operating system interfaces

Source code: Lib/os.py This module provides a portable way of using operating system dependent functionality. If you just want to read or write a file see open(), if you want to manipulate paths, s...

Python documentation

...
Use of "os.listdir()" https://docs.python.org/3/library/os.html#os.listdir is not interchangeable with "os.walk()" as the former does not recurse by itself & the return values are different.

Else, would have just switched the functions:

walker = os.walk if recurse else os.listdir
# Not interested in
# - checking the type or number of elements for the loop variable on each iteration;
# - needing to generate paths correspondingly.
for <?> in walker():
...

#Python

os — Miscellaneous operating system interfaces

Source code: Lib/os.py This module provides a portable way of using operating system dependent functionality. If you just want to read or write a file see open(), if you want to manipulate paths, s...

Python documentation