Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue with Python implementation of assignment chaining

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.

like image 429
skirkpatrick Avatar asked Jul 05 '26 01:07

skirkpatrick


1 Answers

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
like image 60
Martijn Pieters Avatar answered Jul 06 '26 15:07

Martijn Pieters



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!