【问题标题】:Python - why can I import modules without __init__.py at all?Python - 为什么我可以在没有 __init__.py 的情况下导入模块?
【发布时间】:2018-03-26 21:04:34
【问题描述】:

我是 Python 新手,但我仍然无法理解为什么我们需要 __init__.py 文件来导入模块。其他的问答我都翻过了,比如this

让我困惑的是我可以导入我的模块没有 __init__py,所以我为什么需要它

我的例子,

index.py
   modules/
      hello/
          hello.py
          HelloWorld.py

index.py,

import os
import sys

root = os.path.dirname(__file__)
sys.path.append(root + "/modules/hello")

# IMPORTS MODULES
from hello import hello
from HelloWorld import HelloWorld

def application(environ, start_response):

    results = []

    results.append(hello())

    helloWorld = HelloWorld()
    results.append(helloWorld.sayHello())

    output = "<br/>".join(results)

    response_body = output

    status = '200 OK'

    response_headers = [('Content-Type', 'text/html'),
                       ('Content-Length', str(len(response_body)))]

    start_response(status, response_headers)

    return [response_body]

模块/hello/hello.py,

def hello():
    return 'Hello World from hello.py!'

模块/hello/HelloWorld.py,

# define a class
class HelloWorld:
    def __init__(self):
        self.message = 'Hello World from HelloWorld.py!'

    def sayHello(self):
        return self.message

结果,

Hello World from hello.py!
Hello World from HelloWorld.py!

只需要这两行,

root = os.path.dirname(__file__)
sys.path.append(root + "/modules/hello")

没有任何__init__py。有人可以解释为什么它以这种方式工作吗?

如果__init__py 是正确的方法,我应该做什么/更改我的代码?

【问题讨论】:

    标签: python python-2.7 mod-wsgi


    【解决方案1】:

    基于this 链接:自 Python 3.3 起

    允许隐式命名空间包意味着可以完全放弃提供__init__.py 文件的要求

    【讨论】:

    • 这应该是公认的答案,因为它回答了问题。
    【解决方案2】:

    __init__.py 用于。包包含相关模块的集合。如果你只是想使用单个模块,则不需要使用__init__.py;只需将单个 .py 文件放在系统路径的某个位置,您就可以导入它。

    包的目的不仅仅是让您在其中导入模块。是将模块组合在一起。这样做的主要好处是,如果一个模块在包中,那么该模块可以使用相对导入从包中导入其他模块。如果你有foo.pybar.py 在同一个包中,那么foo 可以做from . import bar。如果您重组包或更改其名称,这会使包内导入更紧凑且更容易重组。

    另外,一个明显的好处是。 . .如果你把它做成一个包,你就不必每次想从它导入东西时都做sys.path 的东西。

    【讨论】:

    • 包的另一大优势是分离命名空间。如果您编写自己的json 模块,它将影响全局json 模块。但是如果你把它设为mypackage.json,它就不会引起这样的冲突(至少在Python 3 或Python 2 中使用from __future__ import absolute_import)。
    • 谢谢。你能给我看一个需要__init__.py的包的例子吗?谢谢。
    • @teelou:在 Python 3.3 之前的版本中,所有包都要求有一个__init__.py 文件。 Python 3.3 删除了此要求,请参阅PEP 420。听起来你可能对包不太了解,所以在阅读 PEP 之前,你可能想先阅读the appropriate section of the Python docs
    【解决方案3】:

    我认为这可能与您使用的 Python 版本有关。我做了一些实验,发现有以下结构:

    jedrzej@jedrzej-UX303LB ~/temp $ tree .
    .
    ├── main.py
    └── packages
        ├── file.py
        └── file.pyc
    
    1 directory, 5 files
    

    main.py 的内容:

    import packages.file as p
    p.fun()
    

    file.py 的内容:

    import sys
    def fun():
      print(sys.path)
    

    当我使用 Python 2.7.12 执行 main.py 时,我得到了 ImportError,而使用 Python 3.5.2 执行 main.py 则可以正常工作。

    在包目录中添加__init__.py 后,代码适用于两个版本的 Python。

    【讨论】:

      【解决方案4】:

      名为 __init__.py 的文件用于将磁盘上的目录标记为 Python 包目录。如果你有文件

      modules/spam/__init__.py
      modules/spam/module.py
      

      并且modules在你的路径中,你可以将module.py中的代码导入为

      import spam.module
      

      from spam import module
      

      如果您删除 __init__.py 文件,Python 将不再在该目录中查找子模块,因此尝试导入模块将失败。

      __init__.py 文件通常是空的,但可用于以更方便的名称导出包的选定部分、保存方便的函数等。鉴于上面的示例,可以使用以下命令访问 init 模块的内容

      import spam
      

      最后是官方文档对这个文件的看法:

      需要__init__.py 文件才能使 Python 处理 包含包的目录;这样做是为了防止 具有通用名称的目录,例如字符串,来自 无意中隐藏了稍后出现的有效模块 模块搜索路径。在最简单的情况下,__init__.py 可以 是一个空文件,但也可以执行初始化代码 用于包或设置__all__ 变量,稍后介绍。

      【讨论】:

      • mydir/spam/__init__.py mydir/spam/module.py 与我的示例中的modules/hello/hello.py 不同?
      • 不,@teelou,它们不是同一个字符串。但他们很相似。它旨在作为一个抽象示例来帮助概括该概念。但是我已经编辑了文件以使抽象消失并减轻负担。祝你好运。
      • 你在哪里使用import spam.module?入口点在哪里——比如 index.py?
      • 你可以在任何其他 python 文件中使用import spam module,只要modules在你的路径上。抱歉,我不确定您所说的入口点是什么意思。在此线程中也阅读@BrenBarn 的答案。很有见地。
      【解决方案5】:

      我认为这是一个很好的'answer',因为我不明白。

      myMath/
          __init__.py
          adv/
              __init__.py
              sqrt.py
              fib.py
          add.py
          subtract.py
          multiply.py
          divide.py
      

      myMath/__init__.py

      from add import add
      from divide import division
      from multiply import multiply
      from subtract import subtract
      from adv.fib import fibonacci
      from adv.sqrt import squareroot
      

      index.py

      import sys
      
      sys.path.append('C:\Users\mdriscoll\Documents')
      
      import mymath
      
      print mymath.add(4,5)
      print mymath.division(4, 2)
      print mymath.multiply(10, 5)
      print mymath.fibonacci(8)
      print mymath.squareroot(48)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-08-22
        • 1970-01-01
        • 2018-01-13
        • 1970-01-01
        • 2016-06-14
        • 2013-04-21
        • 2018-09-21
        相关资源
        最近更新 更多