0

I have the following function-in-function definition (see below).

When I ran >>> pd = distrib(10,listAll) I get this (note the line number correspond to the lines in my file not in the sample below)

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "transportOpt.py", line 78, in distrib
N = NN(0,t1)
File "transportOpt.py", line 48, in NN
print(p1,p2)
NameError: global name 'p1' is not defined

The function itself

def distrib(Nm,lf):
    l = len(lf)
    pd = {}# the output dictionary distribution
    sumpd = 0# the total number of samples

    p1=0
    p2=0
    buf=[lf[0]]
    def NN(a,b):
        global p1,p2
        print(p1,p2)
        y = max(a,b)
        x = min(a,b)
        if y>p2:
            for j in range(p2-p1+1,y-p1+1):
                buf.append(buf[j-1]+lf[j])
            p2 = y
        if x>p1:
            for j in range(0,x-p1):
                buf.pull(j)
            p1 = x
        return buf[b-p1]-buf[a-p1]

    def UpdateDistrib(a,b):
        global sumpd
        tao = t1-t0
        if tao < 0:
            print('UpdateDistrib: t1<t0: mistake')
        if tao == 0:
            tao = 1
        CurrentCount = pd.get(tao,0)
        pd[tao] = CurrentCount + 1.
        sumpd = sumpd + 1.

    def normdistrib():
        for i in pd.keys():
            num = pd[i]
            pd[i] = num/sumpd

    for t1 in range(l):
        N = NN(0,t1)
        if N>Nm:
           UpdateDistrib(0,t1)
           break
    if t1==l-1 and N<=Nm:
        normdistrib()
        return pd
    for t0 in range(1,l):
        N = NN(t0,t1)
        if N<=Nm:
            if t1==l-1:
                normdistrib()
                return pd
            r = range(t1+1,l)
            for t1 in r:
                N = NN(t0,t1)
                if N>Nm:
                    UpdateDistrib(t0,t1)
                    break
        else:
            UpdateDistrib(t0,t1)
    normdistrib()
    return pd

What's wrong? Do I use "global" in the wrong way?

Bach
  • 6,145
  • 7
  • 36
  • 61

3 Answers3

3

Maybe you think global p1 makes the name p1 refer to the variable defined with p1=0 on an earlier line. It doesn't do that, because that earlier variable is not a global, it's local to the function distrib.

You don't need global to refer to an outer variable when defining a nested function. However you cannot (by any reasonable means) assign to an outer variable from a nested function in Python 2.7. You need nonlocal for that, and it's only in Python 3.0+. The fact that you have an assignment to p1 in the nested function prevents the name referring to p1 in the outer function, and using global won't help.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
1

Have you defined p1 outside of distrib? That could be your problem, since p1 and p2 are still being used in the distib function they are 'enclosed' and python will know which variables to manipulate. Get rid of the global delcarion entirely and it should work. More on scope: Short Description of the Scoping Rules? Notice the LEGB rule. Local, Enclosed, Global, Built-in

Community
  • 1
  • 1
Pski17
  • 63
  • 5
  • Thanks! No, I didn't use p1 or p2 somewhere else in the file. If I drop global Spider makes a worning about variables used before first attachment. – Igor Traskunov May 06 '14 at 17:20
  • Is Spider a text editor? If so it probably reads the line `print (p1,p2)` and doesn't find p1 and p2 in the NN function and thinks you will get an error. Python is smarter than Spider and will first search NN (Local) for p1 and p2, then distirb (Enclosed), then the rest of your file (Global), then Python's built in methods. – Pski17 May 06 '14 at 17:22
  • The truth is, the interpreter does really throw out the error when I drop global. Now I see that I misunderstood the scope rules when it comes to nested functions (I actually haven't used them before). NN evaluation ignores namespace level of distrib, starting to look right into the module global namespace. Which I don't like since I want everything inside distrib to be forgotten after the execution. Yet I don't know still why it is so (through documentation). But I decided to use nested class and its methods instead of nested functions, since here the name binding is obvious. @Pski17 – Igor Traskunov May 07 '14 at 08:22
1

You have to define p1 and p2 outside of the function 'distrib(Nm,lf):'. Global function is used to change variable values that are outside of the original function, not to import them to sub -def's.

p1 = 0
p2 = 0

def distrib(Nm,lf):
    l = len(lf)
    pd = {}# the output dictionary distribution
    sumpd = 0# the total number of samples

    buf=[lf[0]]
    def NN(a,b):
        global p1,p2
        print p1,p2
Miro K.
  • 345
  • 1
  • 4
  • 13
  • Could you suggest the right place where the rules on global are presented? Official tutorial doesn't clarify it for me. If I drop global, wouldn't p1 and p2 loose any bond with those p1 and p2 one level above, in distrib? – Igor Traskunov May 06 '14 at 17:24
  • Don't drop the global, you need it to 'call' those variables to NN -function, but you have to define p1 and p2 outside of the main def. There aren't much rules about this, this was best what i could find: https://docs.python.org/release/2.4/ref/global.html which is pretty much the same than official tutorial page. – Miro K. May 06 '14 at 17:39