Python 中 inside-class 和 outside-class 导入之间的误解差异

Misunderstanding differences between inside-class and outside-class imports in Python

上下文:我正在写一个翻译器,从一个 Python API 到另一个,都在 Python 3.5+ 中。我使用名为 FileLoader 的 class 加载要翻译的文件,由 Fileloader.py 描述。这个文件加载器允许我将文件的内容传输给其他 class 执行翻译工作的人。

描述每个 class 的所有 .py 文件都在同一个文件夹中

我尝试了两种不同的方法来将我的 FileLoader 模块导入到包含 classes 执行翻译工作的其他模块中。一个似乎有效,但另一个没有,我不明白为什么。

以下是说明这两种方式的两个代码示例:

工作方式

import FileLoader

class Parser:
    #
    def __init__(self, fileLoader):
         if isinstance(fileLoader, FileLoader.FileLoader)
             self._fileLoader = fileLoader
         else:
             # raise a nice exception

崩溃的方式

class Parser:

    import FileLoader
    #
    def __init__(self, fileLoader):
         if isinstance(fileLoader, FileLoader.FileLoader)
             self._fileLoader = fileLoader
         else:
             # raise a nice exception

我认为在 class 的范围内进行导入(这是唯一使用 FileLoader 的范围)就足够了,因为它知道如何与 FileLoader 模块及其内容。我显然错了,因为这是第一种方法。

关于 Python 中的范围,我遗漏了什么?还是有什么不同?

2 件事:这行不通。而且这样做没有任何好处。

首先,为什么不呢?

class Parser:


    #this assigns to the Parser namespace, to refer to it
    #within a method you need to use `self.FileLoader` or 
    #Parser.FileLoader
    import FileLoader

    #`FileLoader` works fine here, under the Parser indentation 
    #(in its namespace, but outside of method)
    copy_of_FileLoader = FileLoader

    #
    def __init__(self, fileLoader):
         # you need to refer to modules under in Parser namespace
         # with that `self`, just like you would with any other
         # class or instance variable 
         if isinstance(fileLoader, self.FileLoader.FileLoader)
             self._fileLoader = fileLoader
         else:
             # raise a nice exception

    #works here again, since we are outside of method,
    #in `Parser` scope/indent.
    copy2_of_FileLoader = FileLoader

其次它不是 Pythonic 并且它没有帮助

Python 社区的惯例是将 import FileLoader 放在程序的顶部。由于它似乎是您自己的模块之一,因此它会在 std 库导入之后和第三方模块导入之后进行。你不会把它放在 class 声明下。

除非...你有一个很好的理由(实际上可能很糟糕)。

我自己的代码,这并不能很好地反映在我身上,有时会有类似的东西。

class MainManager(batchhelper.BatchManager):
    ....

    def _load(self, *args, **kwargs):
      from pssystem.models import NotificationConfig

所以,在说明这不是一件好事之后,我为什么要这样做?

好吧,我的代码在某些特定情况下会出现在这里。这是一个 批处理、命令行、 脚本,可在 Django 上下文中使用,它使用一些 Django ORM 模型。为了使用这些,需要先导入 Django,然后进行设置。但在这些类型的批处理程序的上下文中,这经常发生得太早,我得到 循环导入错误,Django 抱怨它尚未初始化 .

解决办法?延迟执行直到调用方法,当所有其他模块都已导入并且 Django 已在别处设置时。

NotificationConfig 现在可用,但仅在该方法内可用,因为它是其中的局部变量。它有效,但是... 这真的不是很好的做法。

记住:全局范围内的任何东西都会在模块加载时执行,classes 下的任何东西都会在模块加载时执行,任何带有 method/function 主体的东西都会在 method/function 是 .

#happens at module load time, you could have circular import errors
import X1 

class DoImportsLater:
    .

    #happens at module load time, you could have circular import errors
    import X2

    def _load(self, *args, **kwargs):
        #only happens when this method is called, if ever
        #so you shouldn't be seeing circular imports
        import X3

  • import X1是标准做法,Pythonic.

  • import X2,正在做的,不是也没有帮助

  • import X3,我所做的是一种 hack,并且掩盖了循环导入引用。但它“解决”了这个问题。