Python 中的好或坏实践:在文件中间导入

发布于 2024-07-29 22:36:22 字数 466 浏览 3 评论 0 原文

假设我有一个相对较长的模块,但只需要一次外部模块或方法。

在模块中间导入该方法或模块是否被认为可以?

或者导入应该仅位于模块的第一部分。

示例:

import string, pythis, pythat
...
...
...
...
def func():
     blah
     blah 
     blah
     from pysomething import foo
     foo()
     etc
     etc 
     etc
...
...
...

请证明您的答案并添加指向 PEP 的链接或相关来源

Suppose I have a relatively long module, but need an external module or method only once.

Is it considered OK to import that method or module in the middle of the module?

Or should imports only be in the first part of the module.

Example:

import string, pythis, pythat
...
...
...
...
def func():
     blah
     blah 
     blah
     from pysomething import foo
     foo()
     etc
     etc 
     etc
...
...
...

Please justify your answer and add links to PEPs or relevant sources

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

蓝咒 2024-08-05 22:36:22

PEP 8 权威地指出:

导入总是放在最前面
文件,紧接在任何模块之后
注释和文档字符串,以及模块全局变量和常量之前。

PEP 8 应该是任何“内部”风格指南的基础,因为它总结了核心 Python 团队发现的最有效的总体风格(当然,与任何其他语言一样,也存在个人异议,但共识并且 BDFL 同意 PEP 8)。

PEP 8 authoritatively states:

Imports are always put at the top of
the file, just after any module
comments and docstrings, and before module globals and constants.

PEP 8 should be the basis of any "in-house" style guide, since it summarizes what the core Python team has found to be the most effective style, overall (and with individual dissent of course, as on any other language, but consensus and the BDFL agree on PEP 8).

一百个冬季 2024-08-05 22:36:22

2001 年,Python 邮件列表上对此主题进行了详细讨论:

https://mail.python.org/pipermail/python-list/2001-July/071567.html

以下是该线程中讨论的一些原因。 Peter Hansen 指出,以下是不将导入全部放在文件顶部的三个原因:

导入函数的可能原因:

  1. 可读性:如果仅需要导入一个
    功能,并且不太可能改变,
    只放在那里可能会更清晰、更干净。

  2. 启动时间:如果没有外部导入
    函数定义的,它不会执行
    当你的模块第一次被另一个模块导入时,但是
    仅当调用其中一个函数时。 这
    延迟导入的开销(或避免它
    如果这些函数可能永远不会被调用)。

  3. 总是有比这些更多的原因
    到目前为止我们已经想到了。

范罗森(van Rossum)插话了第四个:

  • 开销:如果模块导入很多模块,
    很有可能只有少数人会真正这么做
    使用。 这与“启动时间”类似
    原因,但更进一步。 如果一个脚本
    使用你的模块只使用了一小部分
    它可以节省相当多的时间,特别是
    如果可以避免的进口也大量进口
    模块数。
  • 提供第五种是因为本地进口是避免循环进口问题的一种方式。

    请随意阅读该主题以进行完整的讨论。

    There was a detailed discussion of this topic on the Python mailing list in 2001:

    https://mail.python.org/pipermail/python-list/2001-July/071567.html

    Here are some of the reasons discussed in that thread. From Peter Hansen, here are three reasons not to have imports all at the top of the file:

    Possible reasons to import in a function:

    1. Readability: if the import is needed in only one
      function and that's very unlikely ever to change,
      it might be clearer and cleaner to put it there only.

    2. Startup time: if you don't have the import outside
      of the function definitions, it will not execute
      when your module is first imported by another, but
      only when one of the functions is called. This
      delays the overhead of the import (or avoids it
      if the functions might never be called).

    3. There is always one more reason than the ones
      we've thought of until now.

    Just van Rossum chimed in with a fourth:

    1. Overhead: if the module imports a lot of modules,
      and there's a good chance only a few will actually
      be used. This is similar to the "Startup time"
      reason, but goes a little further. If a script
      using your module only uses a small subset of the
      functionality it can save quite some time, especially
      if the imports that can be avoided also import a lot
      of modules.

    A fifth was offered as local imports are a way to avoid the problem of circular imports.

    Feel free to read through that thread for the full discussion.

    深海少女心 2024-08-05 22:36:22

    其他人都已经提到了 PEP,但也要注意关键代码中间不要有 import 语句。 至少在Python 2.6下,当函数有import语句时,还需要多条字节码指令。

    >>> def f():
        from time import time
        print time()
    
    >>> dis.dis(f)
      2           0 LOAD_CONST               1 (-1)
                  3 LOAD_CONST               2 (('time',))
                  6 IMPORT_NAME              0 (time)
                  9 IMPORT_FROM              0 (time)
                 12 STORE_FAST               0 (time)
                 15 POP_TOP             
    
      3          16 LOAD_FAST                0 (time)
                 19 CALL_FUNCTION            0
                 22 PRINT_ITEM          
                 23 PRINT_NEWLINE       
                 24 LOAD_CONST               0 (None)
                 27 RETURN_VALUE
    
    >>> def g():
        print time()
    
    >>> dis.dis(g)
      2           0 LOAD_GLOBAL              0 (time)
                  3 CALL_FUNCTION            0
                  6 PRINT_ITEM          
                  7 PRINT_NEWLINE       
                  8 LOAD_CONST               0 (None)
                 11 RETURN_VALUE  
    

    Everyone else has already mentioned the PEPs, but also take care to not have import statements in the middle of critical code. At least under Python 2.6, there are several more bytecode instructions required when a function has an import statement.

    >>> def f():
        from time import time
        print time()
    
    >>> dis.dis(f)
      2           0 LOAD_CONST               1 (-1)
                  3 LOAD_CONST               2 (('time',))
                  6 IMPORT_NAME              0 (time)
                  9 IMPORT_FROM              0 (time)
                 12 STORE_FAST               0 (time)
                 15 POP_TOP             
    
      3          16 LOAD_FAST                0 (time)
                 19 CALL_FUNCTION            0
                 22 PRINT_ITEM          
                 23 PRINT_NEWLINE       
                 24 LOAD_CONST               0 (None)
                 27 RETURN_VALUE
    
    >>> def g():
        print time()
    
    >>> dis.dis(g)
      2           0 LOAD_GLOBAL              0 (time)
                  3 CALL_FUNCTION            0
                  6 PRINT_ITEM          
                  7 PRINT_NEWLINE       
                  8 LOAD_CONST               0 (None)
                 11 RETURN_VALUE  
    
    甜点 2024-08-05 22:36:22

    如果导入的模块不经常使用且导入成本较高,那么中间导入就可以。

    否则,遵循 Alex Martelli 的建议是否明智。

    If the imported module is infrequently used and the import is expensive, the in-the-middle-import is OK.

    Otherwise, is it wise to follow Alex Martelli's suggestion.

    川水往事 2024-08-05 22:36:22

    这通常被认为是不好的做法,但有时这是不可避免的(比如当你必须避免循环导入时)。

    必要时的一个例子:我使用 Waf 来构建我们所有的代码。 该系统分为多个工具,每个工具都在其自己的模块中实现。 每个工具模块都可以实现一个 detector() 方法来检测先决条件是否存在。 其中之一的示例可能会执行以下操作:

    def detect(self):
        import foobar
    

    如果工作正常,则该工具可用。 然后,稍后在同一模块中可能需要 foobar 模块,因此您必须在函数级别范围内再次导入它。 显然,如果它是在模块级别导入的,事情就会完全崩溃。

    It's generally considered bad practice, but sometimes it's unavoidable (say when you have to avoid a circular import).

    An example of a time when it is necessary: I use Waf to build all our code. The system is split into tools, and each tool is implemented in it's own module. Each tool module can implent a detect() method to detect if the pre-requisites are present. An example of one of these may do the following:

    def detect(self):
        import foobar
    

    If this works correctly, the tool is usable. Then later in the same module the foobar module may be needed, so you would have to import it again, at function level scope. Clearly if it was imported at module level things would blow up completely.

    維他命╮ 2024-08-05 22:36:22

    95% 的情况下,您应该将所有导入内容放在文件顶部。 您可能想要执行函数本地导入的一种情况是,如果您必须这样做以避免循环导入。 假设 foo.py 导入 bar.py,并且 bar.py 中的函数需要从 foo.py 导入某些内容。 如果将所有导入放在顶部,则导入依赖于尚未编译的信息的文件时可能会出现意外问题。 在这种情况下,具有函数本地导入可以让您的代码推迟导入其他模块,直到其代码完全编译并且您调用相关函数为止。

    然而,看起来您的用例更多的是为了弄清楚 foo() 来自哪里。 在这种情况下,我更喜欢以下两件事之一:

    首先,而不是

    from prerequisite import foo
    

    直接导入先决条件,然后将其称为先决条件.foo。 增加的冗长性通过提高代码透明度而得到了回报。

    或者,(或结合上述情况)如果您的导入和使用它的地方之间的距离确实很远,则可能是您的模块太大。 需要一个没有其他东西使用的导入可能表明您的代码可以重构为更易于管理的块。

    95% of the time, you should put all your imports at the top of the file. One case where you might want to do a function-local import is if you have to do it in order to avoid circular imports. Say foo.py imports bar.py, and a function in bar.py needs to import something from foo.py. If you put all your imports at the top, you could have unexpected problems importing files that rely on information that hasn't been compiled yet. In this case, having a function local import can allow your code to hold off on importing the other module until its code has been fully compiled, and you call the relevant function.

    However, it looks like your use-case is more about making it clear where foo() is coming from. In this case, I would far prefer one of two things:

    First, rather than

    from prerequisite import foo
    

    import prerequisite directly, and later on refer to it as prerequisite.foo. The added verbosity pays itself back in spades through increased code transparency.

    Alternatively, (or in conjunction with the above) if it's really such a long distance between your import and the place it's being used, it may be that your module is too big. The need for an import that nothing else uses might be an indication of a place where your code could stand to be refactored into a more manageably-sized chunk.

    淡看悲欢离合 2024-08-05 22:36:22

    在文件开头将所有导入分组在一起被认为是“良好的形式”。

    模块可以导入其他模块。 通常但不要求将所有导入语句放在模块(或脚本)的开头。 导入的模块名称放置在导入模块的全局符号表中。

    从这里: http://docs.python.org/tutorial/modules.html

    It is considered "Good Form" to group all imports together at the start of the file.

    Modules can import other modules. It is customary but not required to place all import statements at the beginning of a module (or script, for that matter). The imported module names are placed in the importing module’s global symbol table.

    From here: http://docs.python.org/tutorial/modules.html

    自此以后,行同陌路 2024-08-05 22:36:22

    好吧,我认为在文件开头将所有导入分组在一起是一个很好的做法,因为如果想知道加载了哪些库,每个人都知道去哪里查找

    Well, I think it is a good practice to group all imports together at start of file since everyone knows where to look if want to know which libs are loaded

    一抹淡然 2024-08-05 22:36:22

    PEP8

    导入总是放在最前面
    文件,紧接在任何模块之后
    注释和文档字符串,以及模块全局变量和常量之前。

    限制导入并不是一个坏习惯。 因此,导入仅适用于您使用它的函数。

    我认为,如果导入在块的顶部分组在一起,或者如果您希望它全局地位于文件的顶部,则代码会更具可读性。

    PEP8:

    Imports are always put at the top of
    the file, just after any module
    comments and docstrings, and before module globals and constants.

    It is not bad practice to have scopped imports. So that the import applies only to the function you used it in.

    I think the code would be more readable though if the imports where grouped together at the top of the block or if you want it globally at the top of the file.

    ~没有更多了~
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文