The task is taken from LeetCode. I would appreciate an assessment of whether my coding style follows good practices, and if there are any habits or patterns you would find concerning when working together on a codebase.
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.
My solution (Python3):
# Definition for singly-linked list provided by the platform.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
# My solution
# (Leetcode doesn't really let you put things in an __init__ method in a defined way
# (we don't know if a new instance of Solution will be created for each test case),
# so I didn't have one).
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
self.sumHead: ListNode = ListNode(0)
self.sumLinkedList: ListNode = self.sumHead
self.carry: int = 0
while l1 and l2:
# both numbers still have digits
# Sanity Check
assert self.carry in [0, 1]
self.addDigitAndProcessCarry(l1.val + l2.val + self.carry)
# move to the next node for both numbers
l1 = l1.next
l2 = l2.next
# move to the next node for the sum
if l1 or l2 or self.carry:
self.sumLinkedList.next = ListNode(0)
self.sumLinkedList = self.sumLinkedList.next
for linkedListNotConsumed in [l1, l2]:
# only one linked list has more digits to be processed
while linkedListNotConsumed:
# Sanity Check
assert self.carry in [0, 1]
self.addDigitAndProcessCarry(linkedListNotConsumed.val + self.carry)
# move to the next node
linkedListNotConsumed = linkedListNotConsumed.next
if linkedListNotConsumed or self.carry:
self.sumLinkedList.next = ListNode(0)
self.sumLinkedList = self.sumLinkedList.next
if self.carry:
# Sanity Check
assert self.carry in [0, 1]
self.sumLinkedList.val = 1
return self.sumHead
def addDigitAndProcessCarry(self, value: int) -> None:
if value >= 10:
self.sumLinkedList.val = value - 10
self.carry = 1
else:
self.sumLinkedList.val = value
self.carry = 0
2 Answers 2
Naming
The PEP 8 style guide recommends
snake_case for function and variable names. I realize the LeetCode
site requires you to give the primary function those names, but you would
otherwise name the function as add_two_numbers.
Also, addDigitAndProcessCarry would be add_digit_and_process_carry
For variables, sumHead would be sum_head, etc.
Comments
Many of your comments are helpful. However, this comment is not needed:
# My solution
# (Leetcode doesn't really let you put things in an __init__ method in a defined way
# (we don't know if a new instance of Solution will be created for each test case),
# so I didn't have one).
Again, I realize you added this to explain the LeetCode restrictions.
Documentation
PEP 8 recommends adding docstrings for functions. The docstring would decscribe what the function does and how it does it, similar to the description of the problem in the question:
def add_two_numbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
"""
Given two non-empty linked lists representing two non-negative integers...
"""
DRY
I see this code repeated 3 times:
assert self.carry in [0, 1]
I'm not sure you need to do that check in that many places, but if you do, you could create a helper function for the check to reduce the repetition.
Within the confines of Leetcode's requirements, this is about as straightforward a solution as can be hoped for. A few style suggestions have been pointed out by toolic.
The following code can be simplified a bit:
def addDigitAndProcessCarry(self, value: int) -> None: if value >= 10: self.sumLinkedList.val = value - 10 self.carry = 1 else: self.sumLinkedList.val = value self.carry = 0
If we modulo value by 10, we can assume that is the next digit, and the carry is simply value divided (ensure integer division!) by 10.
def addDigitAndProcessCarry(self, value: int) -> None:
self.sumLinkedList.val = value % 10
self.carry = value // 10
If writing within the confines of Leetcode's Solution class doesn't make sense, you are free to write your own functions and classes outside of it, and then simply wrap your solution in Solution.addTwoNumbers.
LeetCode's data structures
LeetCode's linked list data structure is dumb. It doesn't do nice things like let you iterate over it using built-in functionality in Python. But you don't have to live with that restriction.
You can implement that behavior yourself!
As an example, converting to and from iterators for LeetCode's ListNode:
def list_to_iter(lst):
while lst:
yield lst.val
lst = lst.next
def iter_to_list(i):
try:
cur = head = ListNode(next(i))
except StopIteration:
return
try:
while x := next(i):
cur.next = ListNode(x)
cur = cur.next
except StopIteration:
return head
Note that you might also monkey patch this behavior into ListNode.
-
2\$\begingroup\$ You can get the quotient and remainder in a single operation using the built-in
divmod()function.self.carry, self.sumLinkedList.val = divmod(value, 10)\$\endgroup\$Barmar– Barmar2025年12月13日 14:46:11 +00:00Commented 2 days ago
You must log in to answer this question.
Explore related questions
See similar questions with these tags.