0

I am having difficulty importing a function from another script. Both of the scripts below are in the same directory. Why can't the function from another script handle an object with the same name (arr)?

evens.py

def find_evens():
    return [x for x in arr if x % 2 == 0]

if __name__ == '__main__':

    arr = list(range(11))

    print(find_evens())

import_evens.py

from evens import find_evens

if __name__ == '__main__':

    arr = list(range(11))

    print(find_evens())

Traceback

Traceback (most recent call last):
  File "C:\Users\user\Desktop\import_evens.py", line 7, in <module>
    find_evens()
  File "C:\Users\user\Desktop\evens.py", line 2, in find_evens
    return [x for x in arr if x % 2 == 0]
NameError: name 'arr' is not defined
Aurora0001
  • 13,139
  • 5
  • 50
  • 53
blacksite
  • 12,086
  • 10
  • 64
  • 109
  • try using a relative import: `from .evens import find_evens` – elethan Oct 12 '16 at 14:34
  • 3
    You should pass `arr` in as a function argument instead, and define `find_evens` to take a parameter (e.g. `def find_evens(arr): ...` and calling it with `find_evens(arr)`) – Aurora0001 Oct 12 '16 at 14:34
  • Well, `arr` doesn't get defined in `evens.py` when it is being imported (because then it's not `__main__`). And it won't see the `arr` defined in `import_evens.py`. – deceze Oct 12 '16 at 14:44
  • I *could* pass that as an argument, but I would rather have these functions work on global variables – blacksite Oct 12 '16 at 14:44
  • 6
    No, you wouldn't. Really, trust us, you *don't* want global variables. – deceze Oct 12 '16 at 14:45
  • Add this here for people who find this later. ["Why are global variables evil?"](http://stackoverflow.com/questions/19158339/why-are-global-variables-evil). Thanks for the input, everyone. Always learning new things about coding... – blacksite Oct 12 '16 at 14:55

1 Answers1

4

Modules in python have separate namespaces. The qualified names evens.arr and import_evens.arr are separate entities. In each module, using just the name arr refers to the one local to it, so arr in import_evens is actually import_evens.arr.

Since you are defining arr inside of if __name__ ..., the name arr is only the defined in the executed module. The name evens.arr is never defined.

Further, there is no notion of truly global names. A name can be global to a module, so all entities inside it can use it. Any other module still has to address it as a_module.global_variables_name. It can also be imported as from a_module import global_variables_name, but this is just sugar for importing it and binding it to a new local name.

# same as `from a_module import global_variables_name`
import a_module
global_variables_name = a_module.global_variables_name

What you have shown is best done via parameters to the function:

# evens.py
def find_evens(arr):
    return [x for x in arr if x % 2 == 0]

# import_evens.py
if __name__ == '__main__':
    arr = list(range(11))
    print(find_evens(arr))

If you think it's better to have global variables for this but don't understand how a language uses global variables, it's better not to have global variables.

MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119