2
def min_diff(arry_):
   max_ =0
   temp_ =0
   for i in arry_:
     nonlocal max_
     nonlocal temp_
     if i > max_:
        nonlocal max_
        nonlocal temp_
        temp_ = max_
        max_ =i
   return max_-temp_

I want to use max_ and temp_ outside the loop but I am getting an error

SyntaxError: no binding for nonlocal 'max_' found
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Shailab Singh
  • 89
  • 1
  • 1
  • 9

1 Answers1

4

nonlocal can only applied in functions that have a nested scope. You only get a nested scope when you define your function inside of another function.

Python doesn't have block scopes; the for loop doesn't create a new scope, so you don't need to use nonlocal in a loop. Your variables are available throughout the rest of the function. Just drop the nonlocal statements altogether:

def min_diff(arry_):
    max_ = 0
    temp_ = 0
    for i in arry_:
        if i > max_:
            temp_ = max_
            max_ = i
    return max_ - temp_

In Python, only functions, class definitions and comprehensions (list, set, and dict comprehensions as well as generator expressions) get their own scope, and only functions can act as a parent scope for closures (nonlocal variables).

There is also a bug in your code; if you pass in a list where the first value is also the maximum value in the list, temp_ is set to 0 and then never changes. You won't ever find the second-highest value in that case, because only for the very first i will if i > max_: be true. You'd also need to test if i is greater than temp_ in that case:

def min_diff(arry_):
    max_ = 0
    temp_ = 0
    for i in arry_:
        if i > max_:
            temp_ = max_
            max_ = i
        elif i > temp_:
            temp_ = i
    return max_ - temp_

As a side note: you don't need to use trailing underscores in your local variables. Of all the local names used, only max_ would potentially shadow the built-in max() function, but since you don't use that function at all, using max_ instead of max in your function is not actually a requirement. I'd personally drop all the trailing _ underscores from all the names in the function. I'd also use different names; perhaps highest and secondhighest.

Last but not least, you could just use the heapq.nlargest() function to get those two largest values, efficiently:

from heapq import nlargest

def min_diff(values):
    highest, secondhighest = nlargest(2, values)
    return highest - secondhighest

You may want to add some length checks there; if len(values) < 2 is true, what should happen instead?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • but temp is not used locally in if after removing non local . so i am not getting the desired result – Shailab Singh Nov 08 '16 at 08:34
  • @ShailabSingh: you may have other errors in your code, perhaps, but `nonlocal` is not needed. You didn't give us a [mcve], and without sample input, expected output and actual output I can't help any further. – Martijn Pieters Nov 08 '16 at 08:34
  • @ShailabSingh: presumably you want to find the difference between the two highest numbers? – Martijn Pieters Nov 08 '16 at 08:35
  • @ShailabSingh: for `[5, 10, 9, 16]`, the function produces `6`, the difference between the two highest numbers 16 and 10. If that isn't what you wanted, you'll have to explain (*in your question*) what you expected the function to do instead. – Martijn Pieters Nov 08 '16 at 08:36
  • @ShailabSingh: however, the question as to why you got a syntax error has already been answered. – Martijn Pieters Nov 08 '16 at 08:37
  • yes i understand the question has been answered for the error but there is one problem here i am using other function the temp_ is not behaving the way it is supposed to behave since it becomes 0 – Shailab Singh Nov 08 '16 at 08:40
  • @ShailabSingh: well, yes, for *certain inputs* `temp` will stay `0`. Take `[5, 4, 3, 2, 1]` for example. All values in that list except the first are *lower*. So `temp_ = max_` is set *just once*, when `max_` is still `0`. `max_` is then set to `5` and then the `if i > max_:` condition never matches again. This is just a bug in your code. – Martijn Pieters Nov 08 '16 at 08:49
  • @ShailabSingh: you could fix that by adding `elif i > temp_: temp = i`. – Martijn Pieters Nov 08 '16 at 08:49