1

I'm trying to write a method that counts the number of distinct elements in a BST. This is my code:

def numDistinct(root):

    distinct = 0
    seen = {}

    def private_helper(root):

        if not root: return
        if root.val not in seen:
            seen[root.val] = root.val
            distinct += 1
        private_helper(root.left)
        private_helper(root.right)

    private_helper(root)
    return distinct

However, it gives me the error UnboundLocalError: local variable 'distinct' referenced before assignment. I understand the error, but it seems strange to me that seen, which has the same scope as distinct, doesn't throw the same error (even though it's referenced inside private_helper() before distinct is). To test this I changed distinct to a dict and set it up so I could still use it as a counter: distinct = {'count': 0}. The error stopped and my method started working perfectly. What is going on here? Is there a difference in scope between different data-types?

Sam
  • 2,172
  • 3
  • 24
  • 43
  • I think this is a duplicate of https://stackoverflow.com/questions/21959985/why-cant-python-increment-variable-in-closure – c3st7n Mar 05 '18 at 09:18
  • 3
    @c3st7n Although the question provides solution to the problem, I'm more interested in why it happens, and more specifically, why it doesn't happen with dicts. – Sam Mar 05 '18 at 09:20
  • Possible duplicate of [Python variable scope error](https://stackoverflow.com/questions/370357/python-variable-scope-error) – Aran-Fey Mar 05 '18 at 09:29
  • Possible duplicate of [Why can't Python increment variable in closure?](https://stackoverflow.com/questions/21959985/why-cant-python-increment-variable-in-closure) – jpp Mar 05 '18 at 09:30
  • @Sam - https://eli.thegreenplace.net/2011/05/15/understanding-unboundlocalerror-in-python/ this might be a good thing to read, apparently this is a common question on SO and this tries to go into depth on it. – c3st7n Mar 05 '18 at 09:31
  • 1
    Mutating an object (e.g. a dict) is not the same thing as assigning a value to a variable. No assignment = no problem. – Aran-Fey Mar 05 '18 at 09:32
  • Possible duplicate of [Read/Write Python Closures](https://stackoverflow.com/questions/2009402/read-write-python-closures) – quamrana Mar 05 '18 at 09:39

1 Answers1

0

Difference is because of mutability. Dictionary is a mutable object. See when you call distinct inside the function scope, It tries to access the object held by distinct first and tries to rebound the distinct to another object.

distinct += 1
or
distinct = distinct + 1

are same. But in case of dictionary, you rebound a name held by the dictionary. You mutate an already present object.

gautamaggarwal
  • 341
  • 2
  • 11