Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Child cannot use a Module the Parent Imported

I have a funny import error when using Inheritence in Python.

In a parent class I import the module sqlite3, in a child class I then try to use a sqlite3 function but I get an error saying "NameError: global name 'sqlite3' is not defined". Why does this happen & how do I fix it?

The 2 classes are in separate files:

Parent.py

import sqlite3

class Parent:
    def __init__(self):

        self.create_database()

    def create_database(self):
        """ Virtual function to be overriden in child classes """
        pass

    ...more class functions that use sqlite3 functions

Child.py

import Parent

class Child( Parent.Parent ):
    def create_database(self):
        self.db = sqlite3.connect("test.db") # Error occurs HERE

c = Child()
like image 721
sazr Avatar asked Jan 22 '12 00:01

sazr


3 Answers

the sqlite3 module is imported into the Parent module hence you need to access it through that module

self.db = Parent.sqlite3.connect("test.db")

It is not directly imported into the Child module unless you tell python to do so, for example

from Parent import *

Will give you access to all the members of the Parent module from within the Child module

like image 89
babak Avatar answered Oct 21 '22 11:10

babak


The child has its own namespace and you haven't imported sqlite3 into it. So you need to import sqlite3 into Child.py. You could also do import Parent.sqlite3 and then call Parent.sqlite3.connect. There's no real advantage to doing it that way instead of just importing sqlite3, since modules are only actually imported once (at the first import the code reaches) and the following imports just add the module to the current namespace.

like image 34
Glenn Avatar answered Oct 21 '22 11:10

Glenn


You haven't imported the sqlite3 module into the Parent class (you could, but that would be really weird). You've imported sqlite3 into the Parent.py module, which includes the Parent class, and uses the sqlite3 module in its definition.

Then a separate module imports the Parent.py module, and defines a subclass of Parent. This doesn't automatically bring everything in the Parent class into scope[1], and it certainly doesn't bring everything that was in scope when you were defining the Parent class in Parent.py into scope. If you declared other classes in Parent.py, you wouldn't expect those names to be in scope in Child just because they were in the same module as its parent class, so why would you expect this of a module that just happens to be used in defining some of Parent's methods?

You already have a reference to the namespace where sqlite3 was imported; you got the Parent class out of it in order to subclass it when you said class Child(Parent.Parent). So you could use Parent.sqlite3 to access sqlite3, but that's a very odd way to use modules in Python.

Normally it's better to just add import sqlite3 to the top of Child.py. Then anyone reading the code will see that it uses sqlite3. If the see you using sqlite3 that you've imported from Parent.py, they'll wonder why you didn't use the normal way, and think you might be doing something tricky like wrapping the sqlite3 module with some extra code you've added. And if you've just done import * from Parent, then it's not even obvious where the sqlite3 name came from, and your readers will really be confused. And your code will mysteriously stop working when you decide you don't need to import sqlite3 in Parent.py after all, but the error message won't tell you anything about Parent.py.

Generally if you're doing simple obvious things like importing a standard module, you should do it the simple and obvious way. People are used to reading that, and will take it in really easily without needing to stop and think about it. The "confused reader" that is most likely to be a problem is yourself in a a few months when you've forgotten exactly how this code worked; you want to make it as easy as possible for yourself when you get the job of figuring it out again.


[1] Inheriting from a parent class has nothing at all to do with scope, i.e. what names you can access without qualifying them. You don't get access to the parent class' methods and class variables inside the class block defining the child class. What it means is that after the child class is created, the name resolution protocol for instance and class variables will look in the Parent if they don't find things in the child class. This is a somewhat subtle point, that basically boils down to (1) within the child class block (including the definitions of methods) some_parent_method() will give you an error, but (2) after the child class exists (including when methods are actually run) Child.some_parent_method() (or self.some_parent_method() within a method) will find the parent's method.

like image 4
Ben Avatar answered Oct 21 '22 10:10

Ben