I'm writing a linked list for an educational Python library. Here are the important snippets of code:
class Element(object):
def __init__(self, value, next):
self.value = value
self.next = next
class LinkedList(object):
def __init__(self):
self.head = None
self.tail = None
def insert_back(self, element):
if self.empty():
self.insert_front(element)
else:
self.tail.next = Element(element, None)
self.tail = self.tail.next
# I'd like to replace the above two lines with this
# self.tail = self.tail.next = Element(element, None)
My issue comes from the last line. According to the top answer to this question, Python's unique implementation of chained assignment is the culprit.
In other languages, the last line would have the same effect as the two lines above it, but Python evaluates the expression Element(element, None) first and then assigns the result from left-to-right, so self.tail is assigned before self.tail.next. This results in the previous tail element not referencing the new tail element, and the new tail element referencing itself.
My question is: is there a way to perform these two assignments with a single statement?
I'm perfectly content using the more explicit two-line assignment; this is just for curiosity's sake.
Assignment is never chained.
Assignment first evaluates the right-hand expression, then assigns the result to the left-hand targets, one by one, from left to right.
See the assigment statement documentation:
An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.
So your code:
self.tail = self.tail.next = Element(element, None)
effectively means:
result = Element(element, None)
self.tail = result
self.tail.next = result
You could use this instead, simply reversing the assignment order:
self.tail.next = self.tail = Element(element, None)
which assigns in the correct order:
result = Element(element, None)
self.tail.next = result
self.tail = result
This results in the correct behaviour for a linked list:
>>> head = tail = Element(0, None)
>>> tail.next = tail = Element(1, None)
>>> head.value
0
>>> head.next
<__main__.Element object at 0x10262e510>
>>> head.next.value
1
>>> tail is head.next
True
>>> tail.next = tail = Element(2, None)
>>> tail is head.next.next
True
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With