The short answer to this is that, Python is a pass-by-object-reference language, not pass-by-reference as implied in the question. It means that:

  1. result and result_tail are two variables that happen to point at the same value
  2. Mutation / Changing of the underlying value (result_tail.next = ListNode(1)) will affect the value shown by result
  3. However, assigning / pointing the variable result_tail to another value will NOT affect the value of result
  4. result_tail = result_tail.next is assigning the next node of the node that is currently assigned by the variable

The following is an visualization of the values that are assigned to the variables (r = result, rt = result_tail):

result = ListNode(0)
#r
#0 -> None

result_tail = result
#r
#0 -> None
#rt

result_tail.next = ListNode(1)
#r
#0 -> 1 -> None
#rt

result_tail = result_tail.next
#r
#0 -> 1 -> None
#     rt

result_tail.next = ListNode(2)
#r
#0 -> 1 -> 2 -> None
#     rt

result_tail = result_tail.next
#r
#0 -> 1 -> 2 -> None
#          rt

References for additional reading:

  • An article explaining the Python pass-by-object reference style in detail https://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dick/
  • An answer explaining Python's pass-by-object reference style https://stackoverflow.com/a/33066581/12295149
  • Question asking on Python's object reference style Understanding Python's call-by-object style of passing function arguments
Answer from Joseph on Stack Overflow
๐ŸŒ
W3Schools
w3schools.com โ€บ python โ€บ python_dsa_linkedlists.asp
Linked Lists with Python
A Linked List is, as the word implies, a list where the nodes are linked together. Each node contains data and a pointer.
๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ python โ€บ python-linked-list
Python Linked List - GeeksforGeeks
December 11, 2025 - Your All-in-One Learning Portal: GeeksforGeeks is a comprehensive educational platform that empowers learners across domains-spanning computer science and programming, school education, upskilling, commerce, software tools, competitive exams, and more.
๐ŸŒ
Reddit
reddit.com โ€บ r/learnpython โ€บ help me out with listnode
r/learnpython on Reddit: Help me out with ListNode
July 10, 2025 -

Hello all, I completed my 12th this may( high school graduate ) going to attend Engineering classes from next month. So I decided to start LeetCode question. Till now I have completed about 13 questions which includes 9 easy ones, 3 medium ones and 1 hard question( in python language ) with whatever was thought to me in my school, but recently I see many questions in from ***ListNode***, but searching in youtube doesn't shows anything about ListNode but only about Linked list. So kindly suggest me or provide the resources to learn more about it.

Thank you!

๐ŸŒ
Stack Abuse
stackabuse.com โ€บ python-linked-lists
Python Linked Lists
August 25, 2023 - To have a data structure we can work with, we define a node. We'll implement a node as a class named ListNode. The class contains the definition to create an object instance, in this case, with two variables - data to keep the node value, and next to store the reference to the next node in the list.
Top answer
1 of 4
27

The short answer to this is that, Python is a pass-by-object-reference language, not pass-by-reference as implied in the question. It means that:

  1. result and result_tail are two variables that happen to point at the same value
  2. Mutation / Changing of the underlying value (result_tail.next = ListNode(1)) will affect the value shown by result
  3. However, assigning / pointing the variable result_tail to another value will NOT affect the value of result
  4. result_tail = result_tail.next is assigning the next node of the node that is currently assigned by the variable

The following is an visualization of the values that are assigned to the variables (r = result, rt = result_tail):

result = ListNode(0)
#r
#0 -> None

result_tail = result
#r
#0 -> None
#rt

result_tail.next = ListNode(1)
#r
#0 -> 1 -> None
#rt

result_tail = result_tail.next
#r
#0 -> 1 -> None
#     rt

result_tail.next = ListNode(2)
#r
#0 -> 1 -> 2 -> None
#     rt

result_tail = result_tail.next
#r
#0 -> 1 -> 2 -> None
#          rt

References for additional reading:

  • An article explaining the Python pass-by-object reference style in detail https://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dick/
  • An answer explaining Python's pass-by-object reference style https://stackoverflow.com/a/33066581/12295149
  • Question asking on Python's object reference style Understanding Python's call-by-object style of passing function arguments
2 of 4
16

For those reading this in the future: I wanted to debug linked list problems on a local environment so here is what I did.

  1. Modified the Leetcode code for ListNode by including the dunder "repr" method. This is for when you want to print a ListNode to see what its value and next node(s).
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

    def __repr__(self):
        return "ListNode(val=" + str(self.val) + ", next={" + str(self.next) + "})"
  1. Next, I made a recursive function that makes a nested ListNode when you pass in a list. This is so you can test your methods by passing in lists (instead of having to manually make a confusing looking ListNode yourself.
def list_to_LL(arr):
    if len(arr) < 1:
        return None

    if len(arr) == 1:
        return ListNode(arr[0])
    return ListNode(arr[0], next=list_to_LL(arr[1:]))
  1. Here is an example that tests my answer for the "reverseList" problem:
def reverseList(head: ListNode) -> ListNode:
    prev = None
    while head:
        next_node = head.next
        head.next = prev
        prev = head
        head = next_node

    return prev


# test cases
t1 = list_to_LL([1, 2, 3, 4, 5])  #ListNode(val=1, next={ListNode(val=2, next={ListNode(val=3, next={ListNode(val=4, next={ListNode(val=5, next={None})})})})})
t2 = list_to_LL([1, 2])  #ListNode(val=1, next={ListNode(val=2, next={None})})
t3 = list_to_LL([])

# answers
print(reverseList(t1))
print(reverseList(t2))
print(reverseList(t3))
๐ŸŒ
YouTube
youtube.com โ€บ watch
Python: Linked Lists (fast) - YouTube
Linked Lists explained (fast) with animated example, and how to write a Linked List program in Python 3, with add, remove, find and size functions example co...
Published: May 21, 2015
Find elsewhere
๐ŸŒ
DataCamp
datacamp.com โ€บ tutorial โ€บ python-linked-lists
Python Linked Lists: Tutorial With Examples | DataCamp
June 2, 2026 - The main takeaway: linked lists win on insertions and deletions at the head (O(1)), but lose on everything else. If you're not frequently adding or removing elements at the beginning of your data structure, a regular Python list is likely the better choice.
๐ŸŒ
CodeSignal
codesignal.com โ€บ learn โ€บ courses โ€บ getting-deep-into-complex-algorithms-for-interviews-with-python โ€บ lessons โ€บ linked-list-operations-in-python
Linked List Operations in Python
class ListNode: def __init__(self, value=0, next=None): self.value = value # Holds the value or data of the node self.next = next # Points to the next node in the linked list; default is None # Initialization of linked list head = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5)))))
๐ŸŒ
YouTube
youtube.com โ€บ brian faure
Python Data Structures #2: Linked List - YouTube
Code below (some minor improvements have been made since the video was released)... In this video we'll begin by discussing the basics of the linked list dat...
Published: August 26, 2017
Views: 167K
Top answer
1 of 4
7

Summary

I won't dwell on what has already been cited by users toolic and J_H, so I just have a few comments:

Type Hinting

I would suggest that you include type hinting, especially if your functions do not contain docstrings that describe the type of arguments being passed to functions (J_H has suggested this, so pardon if this is too repetitive).

Be More Tolerant of Errors in User Input

If the user does not enter a valid integer in function run_and_add, you essentially quit. You should instead put out the prompt again and give the user as many chances needed to enter valid input. The user can always terminate by entering Ctrl-C if they get stuck.

Strive for Encapsulation and Reusability

I can't stress too strongly that your code is crying out for you to create a LinkedList abstract data type that abstracts the notion of a linked list while encapsulating the actual implementation. To that end, I would use attribute names that begin with '_' where appropriate to suggest that they are "private" and not to be either updated nor depended on existing in the future (such as the next instance attribute of the ListNode class.

The following classes are just one possibility. Note:

  1. There is no print method implemented since printing the entire list is trivial given that the class implements the iterator protocol. Besides, what if you wanted to print to a file? Then a print method would require one or more additional arguments.
  2. The client never explicitly creates ListNode instances.
  3. The linked list keeps explicit track of the final (last) node in the list to provide efficient appending of a node or an entire linked list to the end.

I can envision your using this as a starting point and potentially adding other methods (for example, __eq__ methods to compare nodes and linked lists).

"""A module for creating and manipulating linked lists."""

from abc import ABC, abstractmethod
from typing import TypeVar, Any

LinkedListInstance = TypeVar('LinedListInstance', bound='LinkedList')

class NodeType(ABC):
    @property
    @abstractmethod
    def val(self):
        pass

    @val.setter
    @abstractmethod
    def val(self, val):
        pass

class LinkedList:

    class _ListNode(NodeType):
        """Initialize a new node with some value, val."""

        def __init__(self, val):
            self._val = val
            self._next = None

        @property
        def val(self):
            return self._val

        @val.setter
        def val(self, val):
            self._val = val

        def __repr__(self):
            return f'_ListNode({repr(self._val)})'

        def __str__(self):
            return str(self._val)

    def __init__(self):
        """Create a new, empty linked list."""

        self._head = None
        self._tail = None

    def append_node(self, val: Any) -> LinkedListInstance:
        """Append a new node to the list initialized with val."""

        new_node = LinkedList._ListNode(val)
        if self._head is None:
            self._head = new_node
        else:
            self._tail._next = new_node
        self._tail = new_node

        return self

    def insert_node(self, at_node: NodeType, val: Any) -> LinkedListInstance:
        """Create and insert a new node after the specified at_node node initialized
        with val."""

        if at_node is self._tail:  # special case
            return self.append_node(val)
        node_to_insert = LinkedList._ListNode(val)
        node_to_insert._next = at_node._next
        at_node._next = node_to_insert

        return self

    def append_list(self, linked_list: LinkedListInstance) -> LinkedListInstance:
        """Append a linked list to the current list."""

        if self._head is None:
            self._head = linked_list._head
        else:
            self._tail._next = self._head
        self._tail = linked_list._tail

        return self

    def __iter__(self) -> NodeType:
        """Iterate the list."""

        current = self._head
        while current is not None:
            yield current
            current = current._next

if __name__ == '__main__':
    def insert_node_at_position(linked_list: LinkedList, position: int) -> None:
        for counter, current_node in enumerate(linked_list, start=1):
            print(f"Node at position {counter}: {current_node}")
            if counter == position:
                while True:
                    try:
                        number = int(input("Please insert an Integer: "))
                    except ValueError:
                        print("Not an Integer")
                    else:
                        break
                linked_list.insert_node(current_node, number)
                print("Node added at position:", position)

        print("Updated linked list:")
        for node in linked_list:
            print(node)

    linked_list = LinkedList().append_node(1).append_node(2).append_node(3)
    insert_node_at_position(linked_list, 2)
2 of 4
6

names

class ListNode:

This is a perfectly fine identifier, as-is.

There's no adjacent code that uses other node types. Consider shortening to just Node.

design of Public API

OO

def print_linked_list(head):
...
def add_node(prev_node, node_to_add):
...

These are somewhat unexpected signatures, the sort of thing I might expect in Fortran code. ListNode turned out to be just a very brief @dataclass, with no OO aspect to it. Given a ListNode, we find no methods to call on it for list operations. This works, but makes it a little harder for developers and maintenance engineers to discover your API. For example if I hit a breakpoint() I cannot p dir(node) to find plausible things I might do with a node -- I instead have to scour the codebase for such operations.

Also, your signatures lack ListNode type annotations, so I can't just grep for that or use type-aware IDE features to narrow my search.

I propose some more natural implementations.

    def print_linked_list(self):
        head = self
        while head:
            print(head.val)
            head = head.next

    def add_node(self, node_to_add):
        assert node_to_add.next is None
        node_to_add.next = self.next
        self.next = node_to_add

Consider renaming these to simply .print() and .insert().

interactive input vs parameter

(I am paraphrasing, renaming the vague number to new_val.)

def run_and_add(head, position):
                ...
                new_val = int(input("Please insert an Integer: "))

Prefer to place calls of input() further up in the call stack, such as within def main():, and pass in such a value as a parameter:

def run_and_add(head, position, new_val):

main guard

On which topic, you don't have a main() function, and you really need one. Why? So you or some maintenance engineer can safely import linkedlist when exercising your functions in a test suite. Also, it's convenient to ensure that local variables like first (which are not part of your exported Public API) will disappear when they go out of scope. That way such identifiers won't pollute the module namespace.

def main():
    first = ListNode(1)
    first.next = ListNode(2)
    first.next.next = ListNode(3)
    run_and_add(first, 2)

if __name__ == '__main__':
    main()

single responsibility

run_and_add() is an awkward identifier, suggesting that instead of one we're doing two things. Also I find "run" less than clear.

Consider making caller responsible for passing in an already-created node, and then this could be a simple insert_at_position(head, position, new_node) function.

๐ŸŒ
Reddit
reddit.com โ€บ r/learnprogramming โ€บ how does listnode work in leetcode?
r/learnprogramming on Reddit: How does ListNode work in LeetCode?
July 3, 2024 -

I've decided to tackle my first medium problem on Leetcode, Add Two Numbers (Java), but I've hit a wall. I started by reading the task and looking at the description, but after doing some research I just can't grasp how the ListNode class works. Here is its code:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */

I understand that it is supposed to work similar to the java.util.LinkedList class, but I don't get how. It holds two methods besides the default constructor and they only seem to set the values of int val and ListNode next. I am lost at how this chunk of code creates a singly-linked list, as I learned how to use one, but not how it works under the hood. I thought maybe it had something to do with the keyword "this", but after researching even more I learned that it is used to refer to the class property and not the parameter.

Also, while I was working on this I also wondered, is there a way to check the class files for the standard library or any other library? I want to check the code for the LinkedList and other classes in the future for clarity.

๐ŸŒ
freeCodeCamp
freecodecamp.org โ€บ news โ€บ introduction-to-linked-lists-in-python
Linked Lists in Python โ€“ Explained with Examples
September 22, 2022 - By Fakorede Damilola Different programming languages offer different ways to store and access data. Some of the data structures you can use are collections such as arrays, lists, maps, sets, and so on. These all do an awesome job storing and accessi...
๐ŸŒ
Python documentation
docs.python.org โ€บ 3 โ€บ tutorial โ€บ datastructures.html
5. Data Structures โ€” Python 3.14.7 documentation
December 6, 2023 - This chapter describes some things youโ€™ve learned about already in more detail, and adds some new things as well. More on Lists: The list data type has some more methods. Here are all of the method...
๐ŸŒ
Swarthmore College
cs.swarthmore.edu โ€บ ~knerr โ€บ teaching โ€บ topics โ€บ linkedlists.html
Linked Lists vs Python lists
How about for indexing, or finding the ith item in a list? For the python list, that is an O(1) operation, since it is just a simple calculation to find the correct memory location (base address + i). For the linked list, to get to the ith node, we need to start at the head of the list and move over i times.
๐ŸŒ
CSCI 0112
cs0112.github.io โ€บ Lectures โ€บ lecture19.html
Linked Lists (Part 1) | CSCI 0112 - Fall 2024
October 21, 2024 - Letโ€™s make some classes that let us turn this into something we can write in Python. The picture above is a hint: we should probably have a kind of object to represent those links. class ListNode: def __init__(self, data): self.data = data self.next = None
๐ŸŒ
Real Python
realpython.com โ€บ linked-lists-python
Linked Lists in Python: An Introduction โ€“ Real Python
June 24, 2026 - In this article, you'll learn what linked lists are and when to use them, such as when you want to implement queues, stacks, or graphs. You'll also learn how to use collections.deque to improve the performance of your linked lists and how to implement linked lists in your own projects.
๐ŸŒ
Medium
medium.com โ€บ analytics-vidhya โ€บ a-brief-overview-of-linked-list-in-python-eaf4aa8821be
A brief overview of the Linked list in Python | by Nilson Chapagain | Analytics Vidhya | Medium
August 8, 2021 - A brief overview of the Linked list in Python Linked list A linked list is a list of nodes where each node contains the value stored and the address of the next node. Singly Linked List Singly-linked โ€ฆ
๐ŸŒ
Medium
medium.com โ€บ @shruti.mandaokar โ€บ understanding-singly-linked-lists-in-python-a-beginner-friendly-guide-1dd3432710ee
Understanding Singly Linked Lists in Python โ€” A Beginner-Friendly Guide | by Shruti Mandaokar | Medium
June 12, 2025 - In this post, weโ€™ll break down a simple Python implementation of a singly linked list, line-by-line, and understand the key methods like insertion, printing, searching, and finding the size of the list.
๐ŸŒ
Python Central
pythoncentral.io โ€บ singly-linked-list-insert-node
Singly Linked List: How To Insert and Print Node | Python Central
December 28, 2021 - This simple tutorial explains what linked lists are and how to implement them. It also talks about inserting a node and printing the nodes of a linked list.