views:

229

answers:

7

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?

+1  A: 

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

Martin Beckett
Remember, import happens at run-time. There is no compile time. You don't declare everything. You merely provide a way to resolve the names.
S.Lott
Is that relevant? The import is simply telling the VM which file to look in, it doesn't make any difference when it does that.
Martin Beckett
Think of import basically as combination of #include for the whole file, and change of names xxx -> mod.xxx
ilya n.
But - and I think this is really my question - do I need an import for show_answer to know that it's parameter has an answer() method?
Steve Folly
@Steve, no, you can try to call any method on any object and it will succeed in that object happens to have that method for whatever reason.
ilya n.
+6  A: 

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.

balpha
Indeed, though there are ways around it -- a mod1 class could pass a Universe object to mod2 which could create more instances of it if necessary.
ilya n.
+1  A: 

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.

AlbertoPL
No, it doesn't because import happens before the definition of Universe class.
ilya n.
I somewhat misworded what I meant, I'll correct it to what I meant to say.
AlbertoPL
+1  A: 

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

nik
Indeed, and see more info in the link in my answer.
ilya n.
Oops, yes, you're right. I trimmed down the example code a bit too much. Try to imagine that class Universe is in a module all on it's own!
Steve Folly
+1  A: 

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.
ilya n.
Yep, sorry about the circular import, that was a mistake on my part. My question was, though: is it true that mod2 *doesn't* need to know how Universe is implemented? I could just as well pass an ExamQuestion object to show_answer just so long as it has an answer() method?
Steve Folly
Yep. So it is. I think this makes Python easier to understand. Though some people complain this makes it possible to make a mistake of calling a method on a wrong type, I have yet to see this in practice.
ilya n.
+3  A: 

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.

Alex Martelli
A: 

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..)

dbr
Well, eval (open(...).read()) is closer to what you meant, I guess...
ilya n.
It'd be exec(compile(open("m2.py").read(), "m2.py", "exec"))
dbr