Python子级不能使用父级导入的模块

Python子级不能使用父级导入的模块,python,inheritance,import,polymorphism,Python,Inheritance,Import,Polymorphism,在Python中使用继承时,我有一个有趣的导入错误 在父类中,我导入模块sqlite3,然后在子类中,我尝试使用sqlite3函数,但我得到一个错误:“NameError:未定义全局名称‘sqlite3’”为什么会发生这种情况?我如何解决它? 这两个类位于不同的文件中: Parent.py import sqlite3 class Parent: def __init__(self): self.create_database() def create_da

在Python中使用继承时,我有一个有趣的导入错误

在父类中,我导入模块sqlite3,然后在子类中,我尝试使用sqlite3函数,但我得到一个错误:“NameError:未定义全局名称‘sqlite3’”为什么会发生这种情况?我如何解决它?

这两个类位于不同的文件中:

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

子项有自己的命名空间,而您尚未将sqlite3导入其中。因此,您需要将sqlite3导入Child.py。您还可以执行
导入Parent.sqlite3
,然后调用
Parent.sqlite3.connect
。这样做而不只是导入sqlite3没有真正的好处,因为模块实际上只导入一次(在第一次导入代码时)下面的导入只是将模块添加到当前名称空间。

sqlite3模块被导入到父模块中,因此您需要通过该模块访问它

self.db = Parent.sqlite3.connect("test.db")
例如,除非您告诉python这样做,否则它不会直接导入子模块

from Parent import *

将允许您从子模块中访问父模块的所有成员

您还没有将
sqlite3
模块导入到
父类
中(您可以,但这真的很奇怪)。您已经将
sqlite3
导入到
Parent.py
模块中,该模块包括
Parent
类,并在其定义中使用
sqlite3
模块

然后,一个单独的模块导入
Parent.py
模块,并定义
Parent
的子类。这不会自动将
Parent
类中的所有内容纳入作用域[1],而且当您在
Parent.py
中定义
Parent
类时,它肯定不会将作用域中的所有内容纳入作用域。如果您在
Parent.py
中声明了其他类,您不会仅仅因为这些名称与其父类在同一模块中,就期望它们在
Child
中的作用域中,那么为什么您会期望这些模块恰好用于定义一些
Parent
的方法呢

您已经有了对导入
sqlite3
的命名空间的引用;当你说
class-Child(Parent.Parent)
时,你从中得到了
Parent
类,以便对它进行子类化。因此,您可以使用
Parent.sqlite3
访问
sqlite3
,但在Python中使用模块是一种非常奇怪的方式

通常,只需将
importsqlite3
添加到
Child.py
的顶部即可。然后任何阅读代码的人都会看到它使用了
sqlite3
。如果用户看到您使用从
Parent.py
导入的
sqlite3
,他们会想知道您为什么没有使用正常的方式,并认为您可能在做一些棘手的事情,比如用添加的一些额外代码包装
sqlite3
模块。如果您刚刚从父级执行了
import*
,那么
sqlite3
名称的来源甚至不明显,您的读者会感到困惑。当您决定不需要在
Parent.py
中导入
sqlite3
时,代码将神秘地停止工作,但错误消息不会告诉您有关
Parent.py
的任何信息

一般来说,如果你正在做一些简单而明显的事情,比如导入一个标准模块,那么你应该以简单而明显的方式来做。人们已经习惯了阅读,并且会很容易地接受它,而不需要停下来想一想。最有可能成为问题的“困惑的读者”是你自己,几个月后,你完全忘记了这段代码是如何工作的;当你重新找到工作时,你想让自己尽可能地轻松



[1] 从父类继承与作用域无关,也就是说,在不限定作用域的情况下可以访问哪些名称。在定义子类的类块中,您无法访问父类的方法和类变量。这意味着在创建子类之后,如果实例和类变量在子类中找不到内容,那么名称解析协议(name resolution protocol)将在父类中查找。这是一个有点微妙的点,基本上可以归结为(1)在子类块内(包括方法的定义)
some\u parent\u method()
会给您一个错误,但是(2)在子类存在后(包括方法实际运行时)
child.some\u parent\u method()
(或
self.some\u parent\u method())
在方法中)将找到父方法。

或者在子模块上简单地使用
导入sqlite3
。您究竟为什么要通过父模块访问sqlite3?另外,“导入*”也不太好。同意,这是一个不好的答案,接受-
import sqlite3
是正确的方法。是的,这是一个不好的答案。您不应该依赖父模块导入提供的sqlite3。为什么不呢?如果它扩展了父级,它不会使用相同的模块吗?或者来自同一父模块的另一个子模块是否会改变导入模块的行为,从而影响其他子模块?像一个疯狂的基因工程实验?