11

I have the following file app.py

class Baz():
    def __init__(self, num):
        self.a = num
        print self.a

def foo(num):
    obj = Baz(num)

and the second file main.py

from app import foo
foo(10)

Running the file python main.py gives the correct output.

Now in the second file, I'm just importing the function not the class, although successful execution of my function requires the class as well.

When importing the function does Python automatically import everything else which is needed to run that function, or does it automatically search for the class in the current directory?

Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
Kartik Anand
  • 4,513
  • 5
  • 41
  • 72

2 Answers2

6

As @DavidZ already mentioned the whole Python file gets compiled when we import it. But another special thing happens when a function body is parsed, a function knows which variables it should look for in local scope and which variables it should look for in global scope(well there are free variables too).

>>> import dis
>>> dis.dis(foo)
  7           0 LOAD_GLOBAL              0 (Baz)
              3 LOAD_FAST                0 (num)
              6 CALL_FUNCTION            1
              9 STORE_FAST               1 (obj)
             12 LOAD_CONST               0 (None)
             15 RETURN_VALUE

So, here Baz must be fetched from global scope.

But how to identify this global scope when we import app.py in another file?

Well, each function has a special attribute __globals__ attached to it which contains its actual global namespace. Hence, that's the source of Baz:

>>> foo.__globals__['Baz']
<class __main__.Baz at 0x10f6e1c80>

So, app's module dictionary and foo.__globals__ point to the same object:

>>>sys.modules['app'].__dict__ is foo.__globals__ 
True

Due to this even if you define another variable named Baz in main.py after importing foo it will still access the actual Baz.

From data-model page:

__globals__ func_globals:

A reference to the dictionary that holds the function’s global variables — the global namespace of the module in which the function was defined.

Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • This is neat. So I should never put unrelated code in one file if my intention is to just load a single function, because Python will always compile the whole file, right? – Kartik Anand Mar 31 '15 at 11:25
  • @KartikAnand Python will compile it only once to a `.pyc` file, later imports simply fetch the bytecode from that same `.pyc` file until you again update the `.py` file. – Ashwini Chaudhary Mar 31 '15 at 11:27
  • So if I am not explicitly importing `Baz`, can I instantiate it by accessing it from `__globals__` attached to the function? – Kartik Anand Mar 31 '15 at 11:30
  • @KartikAnand Yes. Well you can access the whole module using `import sys;sys.modules['app']`. Imports are cached in Python. https://docs.python.org/3/reference/import.html#the-module-cache – Ashwini Chaudhary Mar 31 '15 at 11:33
  • So it's just good practice to import whatever you need instead of accessing it using `sys.modules dict` – Kartik Anand Mar 31 '15 at 11:36
  • @KartikAnand Yes, you can import from a particular module how many times you want because the actual import happens only once. But unnecessary variable imports will only flood your namespace that's the reason `from x import *` are discouraged, so import only those things that are required. To handle implicit imports properly learn how Python's import machinery works. With that said we are moving too much away from your actual question now. :-) – Ashwini Chaudhary Mar 31 '15 at 11:43
3

Python does not automatically do any of these things.

When you import something from a module (in this case, the app module), Python first runs all the code in the corresponding file (app.py). The code in the file app.py which you've written does two things:

  1. define the class Baz
  2. define the function foo

When the function foo runs, Python looks for Baz in the module that foo is part of, and only there. (Well, it also checks local variables defined in the function foo, but you don't have any of those except obj.) Specifically, it looks for app.Baz. If you alter your main.py to do the same search:

from app import foo
foo(10)
import app # same app that was already imported
print app.Baz

you will see that app.Baz is the class you defined in app.py.

If you put the definition of class Baz in yet another file, and if you don't import that file, Python will not run it. This shows that Python does not automatically import dependencies. In particular, suppose app.py contains

def foo(num):
    obj = Baz(num)

and baz.py contains

class Baz():
    def __init__(self, num):
        self.a = num
        print self.a

and main.py is unchanged. You'll get an error because Python has not run the code to define the class Baz.

David Z
  • 128,184
  • 27
  • 255
  • 279
  • I know about the definition part. When it runs the file, does it store the definition part of the Class in some form in the current file? – Kartik Anand Mar 31 '15 at 11:19