前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >怎样合理利用 Python 的 Package

怎样合理利用 Python 的 Package

作者头像
杨丝儿
发布2022-03-01 12:56:37
发布2022-03-01 12:56:37
34300
代码可运行
举报
文章被收录于专栏:杨丝儿的小站杨丝儿的小站
运行总次数:0
代码可运行

python 是通过module组织代码的,每一个module就是一个python文件,但是modules是通过 package 来组织的。

python package 的定义

package 的定义很简单,在当面目录下有 __init__.py 文件的目录即为一个 package 。

不管 __init__.py 是空的还是有内容的,这个目录都会被认为是一个 package ,这是一个标识

Python 的 package 以及 package 中的 __init__.py 共同决定了 package 中的 module 是如何被外界访问的。

__init__.py 内的导入顺序

这个在解决重写的问题时会很有用,探究过程就如这篇博客所说的,这里只放结论。

检查顺序如下:

  1. __init__.py 文件内变量
  2. 是不是 package 内的subpackage
  3. 是不是 package 内的module

__init__.py 的写法

这个文件本质上和我们平常写的python文件没有太大的区别,但是要注意两点:

  1. 保证 __init__.py 轻量化,最小化其中代码的副作用,最好全部打包成函数。
  2. 把本模块里面的公用的method在 __init__.py 的时候暴露出来,这样在其他地方的引用就不需要引用具体位置,只需要引用这个包就好了。

跳转链接: 使用自定义的 package

下面这个原先的版本应该是 python 2 的,python 3 完全不同了,所以进行了一些删减,仅仅作为小知识点。

  • 定义 "__all__" 变量
  • 一个一个导入

到这里我们想到的第一件事情就是把我们的元素都导入,于是我们就想到使用:

代码语言:javascript
代码运行次数:0
复制
from module import *

因为 * 实在是范围太广了,那么如何决定哪些是可以导入的呢?这里我们引入变量 __all__

__all____init__.py 文件中的一个列表型变量,通过定义 __all__ 我们可以规定 from module import * 可以导入的元素有哪些。我们只需要在 __init__.py 中添加一行代码:

代码语言:javascript
代码运行次数:0
复制
__all__ = ["module0", "moduole1", "module2", ···]

之后Python会按顺序逐一导入列表中的元素。

这个就很直接了,我们不使用 * 就一个一个得导入。

导出将按照以下规则执行:

  • 此 package 被导入
  • 执行 __init__.py 中可被执行的代码
  • __init__.py 中定义的 variable 被导入
  • 显式导入的 module 被导入

所以也可以侧面反应我们的 __all__ 变量的作用是怎样的了。能够节省一定的时间。

在 class 已经足以解决大部分问题的当下,为什么需要 package ?

首先随着项目的变大,通过 package 来整理项目变得尤为重要。

Python 是通过 module 组织代码的,module 即一个 py 文件,module 又是通过 package 来组织的, package 是一个包含 __init__.py 的文件夹,代码,module, package 它们三者的关系就是:module 包含代码, package 至少包含一个为 __init__.py 的 module。

这中间没有 class 的概念,class 更多是面向对象的时候使用的,可以作为 module 中的一个元素。

使用自定义的 package

跳转链接:init.py 的写法

这里有一个盲区,我们在使用 package 的时候往往不会放在某一个特定的仓库,只有完全标准化之后的 package 才会放到某一个地方保存好。

问题就来了,我们的工作目录往往不在系统路径下,也就是说没有把当前工作路径添加到System Variable Path。我们无法直接调用同一目录下的 package 。

所以我们需要做的事情是添加一个临时的系统路径,在import之前添加上这个系统路径。

代码语言:javascript
代码运行次数:0
复制
import sys
sys.path.append("upper folder of the package ")

这里我们需要把目标pakage的上层目录添加进path中,这样我们才能找到这个 package 。

如果我们的自定义 package 和 main.py 有相同的系统里路径,那就简单多了。

代码语言:javascript
代码运行次数:0
复制
import sys, os
sys.path.append(os.getcwd())

然后我们有两种使用自定义 package 的方式如下所示。

  • 空白 __init__.py
  • 优化 __init__.py

这种就是比较直接的方法,我们在 main.py 中添加每一个 package 或者 subpackage 的路径,然后直接 import 进来。

代码举例:

代码语言:javascript
代码运行次数:0
复制
# we assume that the DIY package is under cwd
import sys, os
sys.path.append(os.path.join(os.getcwd(), ' package 0', ' package 1'))
sys.path.append(os.path.join(os.getcwd(), ' package 0', ' package 2'))

import package 0. package 1.module0
import package 0. package 2.module1

这个如果要分类的话属于递归调用的方法,我们在每一层的 __init__.py 将路径临时添加进path中,保证了只要我们的最外层 package 的在path中了,我们剩下的 subpackage 都可以被索引到。

因此我们不需要再对我们的 main.py 做任何修改了。我们需要做的事情只有在每一个 __init__.py 中添加一层当前文件夹。

具体代码如下:

代码语言:javascript
代码运行次数:0
复制
import sys, os
sys.path.append(os.path.join(os.getcwd(), 'subpackage '))

from subpackage import *

阅读 __init__.py 源码后发现大家写得都不太一样。但是相信基本思想就这些了,应该出入不大了。

小知识点

python中 r'string',b'string',u'string',f'string' 的含义:

字符

含义

r/R

非转义的原始字符串

b

bytes

u/U

表示unicode字符串

f/format()

格式化操作

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-12-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • python package 的定义
  • __init__.py 内的导入顺序
  • __init__.py 的写法
  • 在 class 已经足以解决大部分问题的当下,为什么需要 package ?
  • 使用自定义的 package
  • 小知识点
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档