[Tutor] Confusion regarding the 'from' statement

Dave Angel d at davea.name
Wed Aug 15 03:04:20 CEST 2012


On 08/14/2012 04:00 PM, eryksun wrote:
> On Tue, Aug 14, 2012 at 2:24 PM, Mazhar Hussain <yam.matt at gmail.com> wrote:
>> #mod1.py
>> from mod2 import test
>> test('mod1.py')
>>
>> #mod2.py
>> def countLines(name):
>>     print len(open(name).readlines())
>>
>> def countChars(name):
>>     print len(open(name).read())
>>
>> def test(name):
>>     print 'loading...'
>>     countLines(name)
>>     countChars(name)
>>     print '-'*10
>>
>> Here when I imported and ran the 'test' function, it ran successfully
>> although I didn't even import countChars or countLines, and the 'from'
>> statement had already deleted the mod2 module object.
>>
>> SO I basically need to know why does this code work although
>> considering the problems I mentioned it shouldn't.
> mod1 gets a reference to mod2.test, but the mod2 object isn't garbage
> collected. A reference exists in sys.modules. After the import, add
> the following:
>
> import sys
> print sys.modules['mod2']
>
> Also test() can access countChars() and countLines() because it was
> defined in the mod2 namespace. In other words, test.__globals__ is
> mod2.__globals__. An example:
>
> #mod1.py
> import mod2
> mod2.test_global()
> print mod2.g
>
> #mod2.py
> def test_global():
>     global g
>     g = "I'm in mod2."
>
> #run python mod1.py
>
> Even though test_global is called from mod1, g is created in mod2.
>
> More namespace trivia...
> When you run a module as the main script, its name is '__main__' and
> other modules can "import __main__". But if you import it by the
> filename, you get a new module instance with a separate namespace:
>
> #mod1
> if __name__ == '__main__':
>     import mod2
>     mod2.imp_main() #create g in __main__ and also in mod1
>     print g  #__main__
>     import mod1  #self import, but mod1 instance, not __main__
>     print mod1.g  #mod1
>
> #mod2
> def imp_main():
>     import __main__
>     import mod1
>     __main__.g = "__main__"
>     mod1.g = "mod1"
>
> #run python mod1.py

I can't tell from your wording if you're recommending this "feature" or
just pointing it out as an anomaly.  There are two "mistakes" happening
in this sample code which can cause real problems in real code:

1) recursive imports.  If anybody has a non-trivial top-level code, or
even certain class-initialization code, this can cause surprising errors.
2) multiple imports under different names.  By importing the "same"
module under the two names __main__ and mod1, you usually end up with
two copies of stuff, and that can break a lot of implicit assumptions in
working code.


-- 

DaveA



More information about the Tutor mailing list