2

In this answer a singleton decorator is demonstrated as such

def singleton(cls):
    instances = {}
    def getinstance():
        print len(instances)
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

but instances is 'local' to each class that is decorated, so I tried to be more efficient and use

def BAD_singleton(cls):
    instances = None
    def getinstance():
        if instances is None:
            instances = cls()
        return instances
    return getinstance

@BAD_singleton
class MyTest(object):
    def __init__(self):
        print 'test'

However, this gives an error

UnboundLocalError: local variable 'instances' referenced before assignment

when m = MyTest() is called

I think I understand which this should not work (as the assignment to instances will be local and be lost between calls), but I do not understand why I am getting this error.

Community
  • 1
  • 1
tacaswell
  • 84,579
  • 22
  • 210
  • 199

1 Answers1

1

The reason for the error is python is cleverer than I am and identified that instances is made local by the assignment and does not go up-scope to find the assignment. As pointed out in the comments by @GeeTransit this is possible in python3 via nonlocal

def nonlocal_singleton(cls):
    instances = None
    def getinstance():
        nonlocal instances
        if instances is None:
            instances = cls()
        return instances
    return getinstance

@nonlocal_singleton
class MyTest(object):
    def __init__(self):
        print('test')
tacaswell
  • 84,579
  • 22
  • 210
  • 199
  • It's been a while, but I'd like to point out that by adding a `nonlocal instances`, you can fix the error. It's raised because the function doesn't see a "declaration" or any sort before the first use of the variable. In this case, `nonlocal instances` would be similar to `instances = some_value` but `some_value` is the same as the one outside. – GeeTransit Sep 11 '19 at 23:15
  • 1
    @GeeTransit Edited accordingly! Thanks! – tacaswell Sep 14 '19 at 15:38