I've been playing around reversing single-linked lists and all works fine but then I decided to add a decorator to time execution of functions. And now I get errors like this when I try to run the code:
Traceback (most recent call last):
File "C:/Users/cherp2/AppData/Roaming/JetBrains/PyCharmCE2020.3/scratches/scratch_7.py", line 86, in <module>
main()
File "C:/Users/cherp2/AppData/Roaming/JetBrains/PyCharmCE2020.3/scratches/scratch_7.py", line 78, in main
print_ll(ll)
File "C:/Users/cherp2/AppData/Roaming/JetBrains/PyCharmCE2020.3/scratches/scratch_7.py", line 10, in wrapped
f(*args, **kwargs)
File "C:/Users/cherp2/AppData/Roaming/JetBrains/PyCharmCE2020.3/scratches/scratch_7.py", line 37, in print_ll
vals.append(str(node.val))
AttributeError: 'NoneType' object has no attribute 'val'
My decorator code is below. I checked and its pretty much the same as in the answer here:
def func_time(f):
def wrapped(*args, **kwargs):
t = dt.datetime.now()
f(*args, **kwargs)
print(f'{f.__name__} -- elapsed: {dt.datetime.now() - t}')
return wrapped
Could the issues come because I'm using recursion in most of the functions? This is the linked list node definition and one of the erring functions:
from dataclasses import dataclass, field
import datetime as dt
from typing import Optional
import random
@dataclass(order=True)
class Node:
val: int
next: 'Node' = field()
def make_ll(n, head: Optional[Node] = None, node: Optional[Node] = None):
if not head:
head = Node(random.randint(0, 20), None)
node = head
node.next = Node(random.randint(0, 20), None)
if n == 0:
return head
else:
return make_ll(n-1, head, node.next)
@func_time
def print_ll(node: Node, vals: Optional[list] = None):
if not vals:
vals = []
vals.append(str(node.val))
if node.next:
return print_ll(node.next, vals)
else:
vals.append('None')
print(' -> '.join(vals))
def main():
ll = make_ll(10, None)
print('Original list: ')
print_ll(ll)
if __name__ == '__main__':
main()
EDIT: Looks like it's definitely an issue with recursion. I tested the decorator on non-recursive functions and it works as expected:
@func_time
def add(l):
running_sum = 0
for a in l:
running_sum += a
return running_sum
>>> l = [i for i in range(10**6)]
>>> x = add(l)
Out: add -- elapsed: 0:00:00.052296
EDIT2: Testing code in the question:
def main():
# ll = make_ll(10, None)
ll = Node(1, None)
ll.next = Node(2, None)
ll.next.next = Node(3, None)
ll.next.next.next = Node(4, None)
ll.next.next.next.next = Node(5, None)
print('Original list: ')
print_ll(ll)
rev = reverse_ll(ll)
print('Reversed list: ')
print_ll(rev)
>>> main()
Out:
Original list:
1 -> 2 -> 3 -> 4 -> 5 -> None
Reversed list:
5 -> 4 -> 3 -> 2 -> 1 -> None