51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 880|回复: 0
打印 上一主题 下一主题

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

[复制链接]
  • TA的每日心情
    无聊
    11 小时前
  • 签到天数: 938 天

    连续签到: 5 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2022-4-15 09:08:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
     package 在 python 中,是一种有效组织代码,module 可以是一个文件,可以通过 import 来导入一个 module 单个文件,而 package 则是作为一个目录来导入。随后我们还会看一看多层嵌套是如何导入的。
    1.  >>> import collections,socket
    2.   >>> print(collections.__path__)
    3.   ['/anaconda3/envs/py38/lib/python3.8/collections']
    4.   >>> print(socket.__path__)
    5.   Traceback (most recent call last):
    6.     File "<stdin>", line 1, in <module>
    7.   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 结构

    1. main.py
    2.   pkg1
    3.   ---__init__.py
    复制代码
     在项目下,我们创建一个文件夹 kpg1 下面有一个文件 __init__.py,这样 package 就是 regular package,这样这个文件夹的名称就是一个 package 名称,我们导入 package 就可以直接导入这个 package 名称。在 __init__.py 文件里添加如下语句。

    1. print("importing pk1")
    2.   def hi_say():
    3.       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() 来。

    1.  print(pkg1.__path__)
    复制代码
    通过 pkg1 的 __path__ 来方法 pkg1 的目录绝对路径。

    1.  print(pkg1.__file__)
    复制代码
     而 __file__ 对应得到 __init__.py 文件的绝对路径。

    1.  print(pkg1.__package__)
    复制代码
    也可以通过 package 的 __package__ 的属性获取 package 的名称,同样可以通过 __name__ 来获取 module 的名称。
      接下来我们进一步加大难度,就是 pkg1 文件夹下再新建一个 mod1.py 文件
    1.  main.py
    2.    pkg1
    3.    ---__init__.py
    4.    ---mod1.py
    复制代码
     __init__.py 文件
    1. print("importing pk1")
    复制代码
    mod1.py 文件中,输出一条"import mod1"的信息,还定义了 say_hi 函数,接下来我们想要做的事导入这个 module 然后执行其中 say_hi 方法。
    1. print("importing mod1")
    2.   def say_hi():
    3.       print("pkg1 say hi")
    复制代码
    1. import sys
    2.   import pkg1
    3.   print('pkg1' in globals())#True
    4.   print('pkg1' in sys.modules)#True
    复制代码
    我们导入 pkg1 这样创建一个指向 module 对象的引用,然后添加全局变量中,同时作为 module 也会被添加到 sys.modules 缓存中。
      然后当我们直接通过 pkg1.mod1 来访问 mod1 module 会抛出下面错误,告诉用户并不存在这个属性
    1.   AttributeError: module 'pkg1' has no attribute 'mod1'
    复制代码
    也就是只是简单导入 package 并不会将其下的 module 一同导入,所以才会出现上面错误。如果想要导入 pkg1 下 mod1 我们需要使用 import pkg1.mod1 这样正确方式来导入 mod1
    1.  import sys
    2.   import pkg1.mod1
    复制代码
    大家注意一下当我们导入 mod1 正确方式是用 import pkg1.mod1,从下面输出来看,python 先执行 __init__.py ,也就是说 python 会先导入 package pkg1 然后再导入 module1 这样顺序。
    1.  importing pk1
    2.   importing mod1
    复制代码
    如果下面方式可以访问到 module mod1 中的 say_hi() 方法。
    1. pkg1.mod1.say_hi()
    复制代码
    1.  print('pkg1' in sys.modules)#True
    2.   print('pkg1.mod1' in sys.modules)#True
    3.   print('pkg1' in globals())#True
    4.   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 对象的内存地址。



    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-4-26 21:05 , Processed in 0.064801 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表