(... the operator, that is 😊).
I haven't used the new walrus operator, := much in code. This is an example of a working mis-use of it.
A new task
I wrote a new task description on Rosetta Code, together with Python recursive and iterative solutions.
The gist of the task is:
- Given a list of integers, >0, representing nesting levels, e.g. [1, 2, 4]
- Generate a tree of those values, in order, in the stated depth of nesting. i.e. [1, [2, [[4]]]]
(Someone on Stackoverflow had that problem, and it seemed like it could form the basis of a good RC task).
Iterative solution
I posted the following code as my iterative solution.
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | def to_tree(x: list) -> list: nested = [] stack = [nested] for this in x: while this != len(stack): if this > len(stack): innermost = [] # new level stack[-1].append(innermost) # nest it stack.append(innermost) # push it else: # this < stack: stack.pop(-1) stack[-1].append(this) return nested |
It works using:
len(stack)
to capture nesting depth; andstack[-1]
as a pointer into the active nest at that level; whilstnested
accumulates the whole tree.
The walrus hack.
I was admiring lines seven to nine above and was initially rthinking about name innermost. It is a kind of temporary variable, but is instrumental in modifying stack. I thought: "could I do lines seven to eight in one statement"?
It is awkward as appends return None, but then the walrus operator came to my rescue and I produced the equivalent:
1
2
3
4
5
6
7
8
9
10
11
12
13 | def to_tree(x: list) -> list: nested = [] stack = [nested] for this in x: while this != len(stack): if this > len(stack): stack.append(None if stack[-1].append(innermost:=[]) else innermost) else: # this < stack: stack.pop(-1) stack[-1].append(this) return nested |
The one statement at lines seven and eight is equivalent. The whole expression is evaluated inside out:
- An empty list is created and assigned to name innermost.
- that same list is nested by appending it to the list at the top of the stack.
- The inner append always returns None which is False in the boolean context of the if condition.
- The else clause is always triggered, returning innermost - the newly created and nested list.
- That newly created and nested list is appended to the head of the stack.
Other uses are Pythonic!
STOP PRESS!
Steven D'Aprano gives valuable insight on this in a comment here.
Hmmm ...
ReplyDelete.append(innermost:=[])
I have to admit, that syntax is really not good at all. I don't know what
guido was thinking there ... python is already quite clean. Not every feature
can or should be part of a programming language.
I've come around a little from initial skepticism: It can be used well I haven't seen it being used badly in code I've read, (except for examples of bad usage such as this), so I am now trying to embrace it!
Delete