关于Python:Python – 为什么我可以导入没有__init__.py的模块?

Python - why can I import modules without __init__.py at all?

我对python还是个新手,但我仍然无法理解为什么我们需要一个__init__.py文件来导入模块。我已经看过其他的问题和答案,比如这个。

让我困惑的是,我可以在没有__init__py的情况下导入模块,那么为什么我需要它呢?

我的例子,

1
2
3
4
5
index.py
   modules/
      hello/
          hello.py
          HelloWorld.py

索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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,

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

模块/hello/helloworld.py,

1
2
3
4
5
6
7
# define a class
class HelloWorld:
    def __init__(self):
        self.message = 'Hello World from HelloWorld.py!'

    def sayHello(self):
        return self.message

结果,

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

只需要这两行,

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

没有任何__init__py。有人能解释一下为什么它是这样工作的吗?

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


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

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

另外,一个明显的好处是。…如果你把它做成一个包裹,你不必每次从里面进口东西时都要做那些东西。


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

1
2
3
4
5
6
7
8
jedrzej@jedrzej-UX303LB ~/temp $ tree .
.
├── main.py
└── packages
    ├── file.py
    └── file.pyc

1 directory, 5 files

main.py的内容:

1
2
import packages.file as p
p.fun()

和file.py的内容:

1
2
3
import sys
def fun():
  print(sys.path)

当我使用python 2.7.12执行main.py时,我得到ImportError,而使用python 3.5.2执行main.py则很简单。

在packages目录中添加__init__.py之后,代码可以与两个版本的python一起工作。


基于这个链接:从Python3.3开始

Allowing implicit namespace packages means that the requirement to provide an __init__.py file can be dropped completely


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

1
2
modules/spam/__init__.py
modules/spam/module.py

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

1
import spam.module

1
from spam import module

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

__init__.py文件通常是空的,但可以用于以更方便的名称导出包的选定部分,保存方便的功能等。在上面的示例中,可以使用

1
import spam

最后,这是官方文件对该文件的看法:

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


我认为这是一个很好的"答案",因为我不明白。

1
2
3
4
5
6
7
8
9
10
myMath/
    __init__.py
    adv/
        __init__.py
        sqrt.py
        fib.py
    add.py
    subtract.py
    multiply.py
    divide.py

我的数学/uu init_uuu.py

1
2
3
4
5
6
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

索引文件

1
2
3
4
5
6
7
8
9
10
11
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)