be careful with local variable scope

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
"""
main idea:  for serialize , do preorder;  for deserilize, use queue to update upper bound and lower bound to detemine if current node is None
"""
class Codec:

    def serialize(self, root: TreeNode) -> str:
        """Encodes a tree to a single string.
        """
        # time O(N) space O(N)
        res = [] #res = ''
        def preorder(node):
            nonlocal res
            if not node:
                return 
            res.append(str(node.val))#res+=str(node.val)+','
            preorder(node.left)
            preorder(node.right)
        preorder(root)
        return ','.join(res)  #res[:-1] 

    def deserialize(self, data: str) -> TreeNode:
        """Decodes your encoded data to tree.
        """
        # time O(N) space O(N)
        if not data: return None
        q = collections.deque(int(val) for val in data.split(','))
        def que(lower, upper):
            if q and lower < q[0] < upper:
                val = q.popleft()
                node = TreeNode(val)
                node.left = que(lower,val)
                node.right = que(val,upper)
                return node
        return que(float('-inf'),float('inf'))
        
        
        

# Your Codec object will be instantiated and called as such:
# Your Codec object will be instantiated and called as such:
# ser = Codec()
# deser = Codec()
# tree = ser.serialize(root)
# ans = deser.deserialize(tree)
# return ans