您的位置:首页 > 脚本大全 > > 正文

python的模块与包与库(Python 中包/模块的 `import` 操作代码)

更多 时间:2021-10-20 08:36:14 类别:脚本大全 浏览量:1321

python的模块与包与库

Python 中包/模块的 `import` 操作代码

用实例来说明 import 的作用吧。

创建以下包结构。一个文件夹 cookfish/,下面包含两个文件, __init__.pycookbook.py

为什么取这几个名字呢?假设我想用 python 去做和鱼相关的菜,这件事情很复杂,所以我给它创建了一个包,名叫cookfish, 既然是包,在它下面必须得创建一个文件__init__.py。烧鱼必备条件之一就是菜谱,所以接着创建了 cookbook.py。这几个文件对我们这次来说就足够了,所以就没有再创建其他文件了。

  • ?
  • 1
  • 2
  • 3
  • cookfish/
  •  __init__.py
  •  cookbook.py
  • 在cookfish/__init__.py中输入如下代码:

  • ?
  • 1
  • 2
  • 3
  • 4
  • __version__ = '0.1'
  • __author__ = 'xie byron'
  • def cookfish_hello():
  •  print("cookfish_hello() from cookfish/__init__.py")
  • cookfish/cookbook.py中输入如下代码:

  • ?
  • 1
  • 2
  • def cookbook_hello():
  •  print("cookbook_hello() from cookbook.py")
  • 提示:下面的实例都是在 python 自带的命令行解释器(windows+python 3.7)中运行的结果。如果你在其他环境下运行,比如jupyter notebook,输出会有差异。

    "import package-name" 都做了什么?

    导入包cookfish。

    >>> import cookfish

    提示:

    如果import时出现错误modulenotfounderror,如下:

  • ?
  • 1
  • 2
  • 3
  • 4
  • >>> import cookfish
  • traceback (most recent call last):
  •  file "<stdin>", line 1, in <module>
  • modulenotfounderror: no module named 'cookfish'
  • 建议先将 python 的当前工作目录设置为 cookfish 的 父文件夹(就是包含cookfish文件夹的文件夹)。命令如下:

  • ?
  • 1
  • 2
  • >>> import os
  • >>> os.chdir(r'path\to\parent\folder\of\cookfish')
  • 用dir操作查看当前命名空间和cookfish命名空间下都有哪些内容。

    >>> dir() # 查看当前命名空间下的对象。注意: cookfish 在当前命名空间下。

  • ?
  • 1
  • ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'cookfish', 'os']
  • >>> dir(cookfish) # 查看 cookfish 命名空间下的对象。

  • ?
  • 1
  • ['__author__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', 'cookfish_hello']
  • 其中的的 __author__, __version__, cookfish_hello 是我们定义的,都导入到了 cookfish 的命名空间下。但是cookfish 下的模块 cookbook.py 没有被导入。这是因为直接 import cookfish 只运行cookfish文件夹下的 __init__.py 文件,不会运行其他模块,所以cookbook没有被导入。

    提示:python 中的模块指后缀 .py的文件,也叫脚本。包 指包含 __init__.py 文件的一个文件夹,一般还会包含其他模块。

    包/模块的命名空间

    这里讲一下我对概念“在cookfish的命名空间下”的理解。

    python 的 import a 会把 a 的python 代码运行一遍,并把运行结果放在一个叫a的命名空间下。

    提示: 如果 a 是包,a 的 python 代码就是 文件夹a下的 __init__.py 中的代码。 如果 a 是模块,那么就是文件 a.py 中的代码。

    import b会把 b 的 python 代码运行一遍,并把运行结果放在一个叫 b 的命名空间下。假设a和b中都有一个叫x的对象, a 中的x在当前命名空间下叫 a.x,b中的x在当前命名空间下叫 b.x,两个x在当前命名空间下不重名。

    提示: 这里的对象 指 python 中的变量/属性,函数,类,实例等等。

    比如__version__属性(或者叫它变量)就在cookfish的命名空间下,我们只能通过 cookfish.__version__ 才能访问到 __version__,直接输入 __version__ 访问不到它,会报错。

    直接输入__version__ 运行会报如下错误:

  • ?
  • 1
  • 2
  • 3
  • 4
  • >>> __version__
  • traceback (most recent call last):
  •  file "<stdin>", line 1, in <module>
  • nameerror: name '__version__' is not defined
  • 其他导入包/模块的方式

    如果我们想导入 cookfish 下的模块 cookbook呢?可以用下面的语法:

  • ?
  • 1
  • >>> import cookfish.cookbook
  • 然后在 cookfish 的命名空间下又多了 cookbook。

  • ?
  • 1
  • 2
  • >>> dir(cookfish)
  • ['__author__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', 'cookbook', 'cookfish_hello']
  • 然后就能通过全名cookfish.cookbook访问cookbook.py中的对象了,比如:

  • ?
  • 1
  • 2
  • >>> cookfish.cookbook.cookbook_hello()
  • cookbook_hello() from cookbook.py
  • 好长的名字啊,能不能短一点啊?当然可以:

  • ?
  • 1
  • >>> import cookfish.cookbook as cb
  • 然后在当前命名空间下就多了对象 cb:

  • ?
  • 1
  • 2
  • >>> dir()
  • ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'cb', 'cookfish', 'os']
  • 然后就能通过别名cb来访问cookbook.py中的对象了,比如:

  • ?
  • 1
  • 2
  • >>> cb.cookbook_hello()
  • cookbook_hello() from cookbook.py
  • 那我能不能只导入cookbook_hello()到当前命名空间?当然可以

  • ?
  • 1
  • >>> from cookfish.cookbook import cookbook_hello
  • 然后 cookbook_hello 就被导入到当前命名空间下了:

  • ?
  • 1
  • 2
  • >>> dir()
  • ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'cb', 'cookbook_hello', 'cookfish', 'os']
  • 然后就能直接访问 cookbook_hello()了,不用任何前缀:

  • ?
  • 1
  • 2
  • >>> cookbook_hello()
  • cookbook_hello() from cookbook.py
  • “from 包/模块名 import *” 是导入所有对象吗?

    那我可以一次性导入 cookfish 下的所有模块、所有包吗?可以也不可以。

    python 有一个条指令

    from 包/模块名 import *

    比如from cookfish import *,给我们的第一感觉是,这条指令是遍历了 cookfish 下的所有文件,找到这个包下面的所有包和模块,把他们统统导入到当前命名空间。

    但不幸的是,这个操作在windows和mac系统上不能很好地实现。因为它们的文件系统不能提供准确的文件名大小写信息。在这两个平台上,python 不知道应该把echo.py导入为模块echo, echo 还是echo,或者其他。(比如windows 95 上面,所有文件名的首字母都会显示为大写)。如果python 把 echo.py导入为 模块echo,但实际python代码中有时按照 echo 使用的,那肯定会报错。[1]

    python 支持大小写,echo和echo是两个不一样的对象

    python 的唯一的解决办法是包的作者提供一个明确的包的索引,告诉 python 在 python 代码中如何命名这个模块。import 语句定义下面一个约定,如果在包的 __init__.py 中定义了一个 __all__ 列表,在 from xxx import * 时,python 就会把 __all__ 列表中的对象导入。

    ! 注意:

    __all__ 只对 from xxx import * 有影响,对其他 import 操作没有任何影响

    在cookfish/__init__.py中, 我们只把函数 cookfish_hello加入__all__ 中,代码如下:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • __all__ = ['cookfish_hello', ] # added to support `from xxx import *`
  • __version__ = '0.1'
  • __author__ = 'xie byron'
  •  
  • def cookfish_hello():
  •   print("cookfish_hello() from cookfish/__init__.py")
  • 重启 python 解释器,在导入之前,先运行 dir()显示当前命名空间的对象。

  • ?
  • 1
  • 2
  • >>> dir()
  • ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'os']
  • ! 注意:

    python 解释器为了提高运行效率,同一个模块只会导入一次。一个模块被导入后,再次运行导入命名不会重新导入。为了显示from xx import * 的特殊性,所以需要重启 python 解释器(就是关闭 python 解释器,然后重新进入)。

    然后运行如下:

  • ?
  • 1
  • >>> from cookfish import *
  • 然后输入 dir() 查看 cookfish_hello()是否被导入到了当前命名空间.

  • ?
  • 1
  • 2
  • >>> dir()
  • ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'cookfish_hello', 'os']
  • 可以看到只有在__all__列表中的 cookfish_hello被导入到当前命名空间,其他什么都没有导入,连cookfish本身也没有被导入。

    所以问题“可以一次性导入 cookfish 下的所有模块、所有包吗?“ 的答案是:是否能一次导入,取决于包的作者有没有把所有子模块/子包都加入到 __all__列表中。

    参考

    [1] built-in package support in python 1.5

    版本

    [1] version 1.0, released on 2019-04-21

    [2] version 1.1, released on 2019-04-21

    添加了 python 命令的输出。运行工具为windows版本python(3.7)自带的命令行解释器。

    原文链接:https://www.cnblogs.com/byronxie/p/10745292.html

    您可能感兴趣