n = 5

class Blah:
    a = n
    n += 42
    b = n

    def foo(self):
        print('Foo: n = {}'.format(n))
        print('Foo: self.n = {}'.format(self.n))
        print('Foo: self.a = {}'.format(self.a))
        print('Foo: self.b = {}'.format(self.b))

def f():
    """ Some function. """
    # comment out the next line => n becomes a local variable
    # => error, since n has not been initialized any value in local scope
    global n
    n += 100

def func():
    # comment both this next line and the assignment of n in func2()
    # => scope is global
    n = 1000
    def func2():
        # comment this next line => scope goes from local to enclosing
        n = 100
        print("func2: n = {}".format(n))
    func2()
    # if we move the declaration of n = 1000 from above to the line below this
    # comment, and n is not assigned a value in func2(),
    # then in func2, n is still considered in enclosing scope,
    # => error because print in func2 references n before assignment
    print("func: n = {}".format(n))

def func3():
    n = 1000
    def func4():
        # n is now in the enclosing scope
        nonlocal n
        n = 100
        print("func4: n = {}".format(n))
    func4()
    print("func3: n = {}".format(n))

def g():
    n = 500
    def gg():
        n = 1000
        def ggg():
            nonlocal n
            n = 100
            print("GGG: n = {}".format(n))
        ggg()
        print("GG: n = {}".format(n))
    gg()
    print("G: n = {}".format(n))

if __name__ == '__main__':
    n = 10
    f()
    blah_object = Blah()
    f()
    print("Global n: {}".format(n))
    blah_object.foo()
    func()
    func3()
    g()
