lsekfe 发表于 2022-4-15 09:08:17

今天来一起聊一聊导入 package 的正确姿势

 package 在 python 中,是一种有效组织代码,module 可以是一个文件,可以通过 import 来导入一个 module 单个文件,而 package 则是作为一个目录来导入。随后我们还会看一看多层嵌套是如何导入的。
 >>> import collections,socket
  >>> print(collections.__path__)
  ['/anaconda3/envs/py38/lib/python3.8/collections']
  >>> print(socket.__path__)
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  AttributeError: module 'socket' has no attribute '__path__'我们看一看 python 提供标注库,例如 collections 和 socket,这里 collections 是一个 package 也就是意味着其是一个目录,在python 文件,而 socket 则是一个 module,对于 socket 和我们之前介绍导入 module 一样。package 与 module 不同就是具有 __path__ 属性,我们可以通过 __path__ 来访问到存放 python 文件的路径。但是对于 module 并不存在这个属性。
  在 python 中,有两种 package,分别是是 regular package 和 namespace package。
  regular package
  我们首先来看一看 regular package,下面是一个 regular package 结构

main.py
  pkg1
  ---__init__.py 在项目下,我们创建一个文件夹 kpg1 下面有一个文件 __init__.py,这样 package 就是 regular package,这样这个文件夹的名称就是一个 package 名称,我们导入 package 就可以直接导入这个 package 名称。在 __init__.py 文件里添加如下语句。
print("importing pk1")
  def hi_say():
      print("pkg1 say hi")在 main.py 我们导入 package 也就是 import pkg1,python 通过 finder 来定位到 package 位置,pathFinder 通过在 sys.path 中的 path 搜索来定位到 package 的位置。大家还记得吗? sys.path 第一个 path 就是我们当前目录,这是为什么 python 可以定位到 pkg1 ,就是根据,当我们导入 package python 就会自动执行 package 下面的 __init__.py 文件。当你 import package 时,module 的编译好 code 对象,我们可以通过 pkg1.hi_say() 来。
 print(pkg1.__path__)通过 pkg1 的 __path__ 来方法 pkg1 的目录绝对路径。
 print(pkg1.__file__) 而 __file__ 对应得到 __init__.py 文件的绝对路径。
 print(pkg1.__package__)也可以通过 package 的 __package__ 的属性获取 package 的名称,同样可以通过 __name__ 来获取 module 的名称。
  接下来我们进一步加大难度,就是 pkg1 文件夹下再新建一个 mod1.py 文件
 main.py
   pkg1
   ---__init__.py
   ---mod1.py __init__.py 文件
print("importing pk1")mod1.py 文件中,输出一条"import mod1"的信息,还定义了 say_hi 函数,接下来我们想要做的事导入这个 module 然后执行其中 say_hi 方法。
print("importing mod1")
  def say_hi():
      print("pkg1 say hi")import sys
  import pkg1
  print('pkg1' in globals())#True
  print('pkg1' in sys.modules)#True我们导入 pkg1 这样创建一个指向 module 对象的引用,然后添加全局变量中,同时作为 module 也会被添加到 sys.modules 缓存中。
  然后当我们直接通过 pkg1.mod1 来访问 mod1 module 会抛出下面错误,告诉用户并不存在这个属性
  AttributeError: module 'pkg1' has no attribute 'mod1'也就是只是简单导入 package 并不会将其下的 module 一同导入,所以才会出现上面错误。如果想要导入 pkg1 下 mod1 我们需要使用 import pkg1.mod1 这样正确方式来导入 mod1
 import sys
  import pkg1.mod1大家注意一下当我们导入 mod1 正确方式是用 import pkg1.mod1,从下面输出来看,python 先执行 __init__.py ,也就是说 python 会先导入 package pkg1 然后再导入 module1 这样顺序。
 importing pk1
  importing mod1如果下面方式可以访问到 module mod1 中的 say_hi() 方法。
pkg1.mod1.say_hi() print('pkg1' in sys.modules)#True
  print('pkg1.mod1' in sys.modules)#True
  print('pkg1' in globals())#True
  print('pkg1.mod1' in globals())#False 通过上面输出我们发现 pkg1 和 pkg1.mod1 都存在于 sys.modules 缓存中,还有不难看出只有 pkg1 位于全局变量,我们只能通过 pkg1 的属性来方法 mod1。
  简单总结一下,我们要方法一个 package 下的 module,首先会访问这个 package 会执行 package 下的 __init__.py 然后再去执行 module 代码,在 sys.modules 保存 pkg1 和 pkg1.mod1 分别指向保存两个 module 对象的内存地址。



页: [1]
查看完整版本: 今天来一起聊一聊导入 package 的正确姿势