Question

mod1.py

import mod2

class Universe:
    def __init__(self):
        pass
    def answer(self):
        return 42

u = Universe()
mod2.show_answer(u)

mod2.py

#import mod1 -- not necessary
def show_answer(thing):
    print thing.answer()

Coming from a C++ background I had the feeling it was necessary to import the module containing the Universe class definition before the show_answer function would work. I.e. everything had to be declared before it could be used.

Am I right in thinking this isn't necessary? This is duck typing, right? So if an import isn't required to see the methods of a class, I'd at least need it for the class definition itself and the top level functions of a module?

In one script I've written, I even went as far as writing a base class to declare an interface with a set of methods, and then deriving concrete classes to inherit that interface, but I think I get it now - that's just wrong in Python, and whether an object has a particular method is checked at runtime at the point where the call is made?

I realise Python is so much more dynamic than C++, it's taken me a while to see how little code you actually need to write!

I think I know the answer to this question, but I just wanted to get clarification and make sure I was on the right track.

UPDATE: Thanks for all the answers, I think I should clarify my question now:

Does mod2.show_answer() need an import (of any description) to know that thing has a method called answer(), or is that determined dynamically at runtime?

Was it helpful?

Solution

import is all about names -- mostly "bare names" that are bound at top level (AKA global level, AKA module-level names) in a certain module, say mod2. When you've done import mod2, you get the mod2 namespace as an available name (top-level in your own module, if you're doing the import itself as top level, as is most common; but a local import within a function would make mod2 a local variable of that function, etc); and therefore you can use mod2.foobar to access the name foobar that's bound at top level in mod2. If you have no need to access such names, then you have no need to import mod2 in your own module.

OTHER TIPS

In this case you're right: show_answer() is given an object, of which it calls the method "answer". As long as the object given to show_answer() has such a method, it doesn't matter where the object comes from.

If, however, you wanted to create an instance of Universe inside mod2, you'd have to import mod1, because Universe is not in the mod2 namespace, even after mod2 has been imported by mod1.

Think of import being more like the linker.
With "import mod2" you are simply telling python that it can find the function in the file mod2.py

Actually, in this case, importing mod1 in mod2.py should not work.
Would it not create a circular reference?

In fact, according to this explanation , the circular import will not work the way you want it to work: if you uncomment import mod1, the second module will still not know about the Universe.

I think this is quite reasonable. If both of your files need access to the type of some specific object, like Universe, you have several choices:

  • if your program is small, just use one file
  • if it's big, you need to decide if your files both need to know how Universe is implemented, perhaps passing an object of not-yet-known type to show_answer is fine
  • if that doesn't work for you, by all means put Universe in a separate module and load it first.

import in Python loads the module into the given namespace. As such, is it as if the def show_answer actually existed in the mod1.py module. Because of this, mod2.py does not need to know of the Universe class and thus you do not need to import mod1 from mod2.py.

I don't know much about C++, so can't directly compare it, but..

import basically loads the other Python script (mod2.py) into the current script (the top level of mod1.py). It's not so much a link, it's closer to an eval

For example, in Python'ish psuedo-code:

eval("mod2.py")

is the same as..

from mod2 import *

..it executes mod2.py, and makes the functions/classes defined accessible in the current script.

Both above snippets would allow you to call show_answer() (well, eval doesn't quite work like that, thus I called it pseudo code!)

import mod2

..is basically the same, but instead of bringing in all the functions into the "top level", it brings them into the mod2 module, so you call show_answer by doing..

mod2.show_answer

Am I right in thinking [the import in mod2.py] isn't necessary?

Absolutely. In fact if you try and import mod1 from mod2 you get a circular dependancy error (since mod2 then tries to import mod1 and so on..)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top