1

I'm new to python and I'm just testing importing a function from one module into another module using from module_name import function. However, when I import the function it also imports and executes a for loop that is not a part of the function but is part of the module.

Module 1:

 from Fibonacci import fibonacci
    fibonacci(10)

Module 2:

def fibonacci(Number):
    for i in range(1,Number+1):
        if i == 1:
            sumCount = 0
            First = 0
        elif i ==2:
            Second = 1
            sumCount = 1
        else:
            sumCount = First + Second
            First = Second
            Second = sumCount 

    print(sumCount)

for F in range(1,10):
    fibonacci(F)

When I import the function fibonacci, the for loop is executed. Why is this and how can I stop this?

Ryan
  • 33
  • 1
  • 8
  • are you sure that the loop which is not part of `def` is executing? – Harsha Biyani Apr 14 '19 at 17:55
  • Yes the output is: 0 1 1 2 3 5 8 13 21 – Ryan Apr 14 '19 at 17:57
  • You could use `if __name__ == "main":`. – Joey Apr 14 '19 at 18:06
  • @youssef That worked but why is it getting pulled through with the function? – Ryan Apr 14 '19 at 18:10
  • `import`s don't work at the AST level -- rather, the *whole module* gets evaluated, then objects in its namespace are pulled out. There are plenty of advantages to that design -- module definitions can contain code that modifies objects in-place, and because the whole module is run at once, all but the very first `import` is very fast, since the resulting object can be cached. – Charles Duffy Apr 14 '19 at 18:23
  • @Ryan Maybe [this](https://stackoverflow.com/a/17347226/9110128) answer is also worth to take a look at. – Joey Apr 14 '19 at 18:31

2 Answers2

3

There is no real mistery on "why" it is executed, python works this way.

The docs say:

The from form uses a slightly more complex process:

  1. find the module specified in the from clause, loading and initializing it if necessary;
  2. for each of the identifiers specified in the import clauses:
    1. check if the imported module has an attribute by that name
    2. if not, attempt to import a submodule with that name and then check the imported module again for that attribute
    3. if the attribute is not found, ImportError is raised.
    4. otherwise, a reference to that value is stored in the local namespace, using the name in the as clause if it is present, otherwise using the attribute name

And also (here the reference):

A module can contain executable statements as well as function definitions. These statements are intended to initialize the module. They are executed only the first time the module name is encountered in an import statement. (They are also run if the file is executed as a script.)

This answer the question "why". Even if you load a single function from your module, the module is still initialized (makes sense to behave this way). Any "free" code hence is executed.

This means that you should not put "free" statements in a module unless they are meant to initialize it.
To prevent this behaviour, use the if __name__ == "main": statement as other answers said. Put inside this if all the code that should be executed only when the module is called directly (for example, code for testing purpose).

Valentino
  • 7,291
  • 6
  • 18
  • 34
1

In Module 2 put the for loop inside the check for if it's main.

def fibonacci(Number):
    for i in range(1,Number):
        ...
    return N

if __name__ == '__main__':
    for F in range(1,10):
        fibonacci(F)

See Here to find out why

kudeh
  • 883
  • 1
  • 5
  • 16
  • 1
    That doesn't answer the question, it is a solution, but he is asking why is the for running if he only imported the function. – Miguel Apr 14 '19 at 17:59
  • Hi, thanks that worked but why is it being imported with the function? – Ryan Apr 14 '19 at 18:02
  • 1
    Hey, see this previous stackoverflow post, [(link)](https://stackoverflow.com/questions/6523791/why-is-python-running-my-module-when-i-import-it-and-how-do-i-stop-it) – kudeh Apr 14 '19 at 18:11
  • @kudeh Thanks that link is pretty useful – Ryan Apr 14 '19 at 18:20