A good solution should enforce modularity and separate concerns, from which a reusable pattern could be distilled. In this case, it would be best to handle the logic of append, neighours and traversal separately. One could save a line of code by creating a dummy node, although it's trivial.
def connect(self, root): def append(l,node): lst,tail=l if not lst: return node,node if not node: return l tail.next=node return lst,node def neighbours(f): fn=None,None # list, tail while f: fn,f=append(append(fn,f.left),f.right), f.next return fn[0] f=root while f: # classic bfs f=neighbours(f)