Ex45: Duplicate import commands?

I have a problem…which I solved…but do not understand why the solution is that way. And I seek illumination…

I have multiple .py files. One file imports the classes of the other. The main file (which imports the classes in the other .py file) also has this…

from textwrap import dedent

And I used dedent in the main .py file and it worked. But then I found that I needed to use it in one of the functions of the classes the main file imports. Whenever I ran the program and the code got to that function in the imported class that had dedent in it I got this error:

NameError: name 'dedent' is not defined

I solved the problem by adding another “from textwrap import dedent” statement into the .py file that had the classes that get imported by the main file.

And that’s what bugs me. I would have thought that the original dedent import line in the main file would have also covered any imported classes that used dedent. But it appears not to. Can someone explain. Does this mean I need to start copying any other import commands into the other .py file(s) just to cover my bases?

Yes, think of each module (file) as a separate unit that needs to be able to run on its own.

Might be worth looking into a base class too if you are worried about duplication.

Weird. I think you might have that first import statement indented under something else, like in a function. Normally nothing you describe should work. :wink:

That’s the thing Zed, my imports are all at the top and all lined up starting at character 1. Same for the other file.

I made a pithy example of the problem. Two files test.py and test2.py. Test.py imports test2.py’s class.

test.py

from textwrap import dedent
from test2 import DedentTestTwo

class DedentTest(object):
    def print_one(self):
        print(dedent("""
                     We are printing from the DedentTest() class!!
                     !!!!
        """))

x = DedentTest()
x.print_one()
y = DedentTestTwo()
y.print_two()

And test2.py

# from textwrap import dedent

class DedentTestTwo(object):
    def print_two(self):
        print(dedent("""
                     We are now printing from the DedentTestTwo() class!!
                     !!!!!
        """))

I commented out the import command in test2.py.

Now when I run test.py I get this in powershell…

PS C:\Users\dswal\AppData\Local\Programs\Python\Python36\Doug> python test.py

We are printing from the DedentTest() class!!
!!!!

Traceback (most recent call last):
  File "test.py", line 14, in <module>
    y.print_two()
  File "C:\Users\dswal\AppData\Local\Programs\Python\Python36\Doug\test2.py", line 5, in print_two
    print(dedent("""
NameError: name 'dedent' is not defined

Now if I uncomment that import command in test2.py and run test.py it works!

PS C:\Users\dswal\AppData\Local\Programs\Python\Python36\Doug> python test.py

We are printing from the DedentTest() class!!
!!!!


We are now printing from the DedentTestTwo() class!!
!!!!!

Zed’s saying this shouldn’t be happening but it is happening. So I’m confused as to why this is working this way. This is saying to me that there can be dependencies imported classes have from the files they were imported from (in this case in the form of a missing import command).

I think I see where your misunderstanding is coming from, and also you should post code like this right away since now it’s easy to explain.

Every file that you use something in needs its own import.

Why?

Because, when you import a file you don’t automatically get all the things it imports. I think you see import as “copy the contents of test2.py into test.py”, so then you think because you did this:

from textwrap import dedent
from test2 import DedentTestTwo

Then it’s like you did did a copy-paste of the contents of dedent, followed by a copy-paste of the contents of DedentTestTwo, and that means DedentTestTwo now has access to dedent.

The import works totally different though. It provides a feature from another module/file to only the file/location where you did the import, and does not leak it anywhere else. Each file gets its own little world.

If you think about it, your idea of “import is copy-paste” would be utter chaos and harder to use. You’d have to know that DedentTestTwo needs dedent imported first, and you’d forget that every time. It’s easier for DedentTestTwo to simply import everything it needs, and test.py to import everything it needs, and to not rely on each other at all.

Am I right on the “import is copy-paste” thinking?

1 Like

I don’t know about “copy -paste”…more like “have access to the class being imported which would now be governed by the rules of the file doing the importing” which I guess is a different way of saying the same thing.

But I get what you’re saying.

A free service run by Zed A. Shaw for learncodethehardway.org.