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,并且掩盖了循环导入引用。但它“解决”了这个问题。
上下文:我正在写一个翻译器,从一个 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,并且掩盖了循环导入引用。但它“解决”了这个问题。