python学习笔记5.3-包的创建

包,也可以称为库,是具有很多功能的一个集合体。本文主要介绍如何自己创建一个包,以及介绍一些在包的创建过程中的技巧。

1. 包的创建

本文的例子将使用最复杂的情况,也就是包目录下含有许多子包,子包中包含许多模块。

/project
    /subpjt1
        __init__.py
        a.py
        b.py

    /subpjt2
        __init__.py
        c.py
        d.py
    __init__.py
test.py

test.py 文件是我们在包外运行的文件,包名定义为project,包含两个子包subpjt1和subpjt2,两个子包分别包含a,b和c,d两个模块。我们注意到每个包目录都有__init__.py这个文件,稍后会讲解它的作用,a.py中有一下代码:

def func_a():
    print('this is func a')

此时所有的__init__.py文件中都为空,不写任何内容。调用func_a:

from project.subpjt1.a import func_a
import project.subpjt1.a.func_a   # 与上一句一样的功能

func_a()

以上是最普通的做法,下面介绍一些高级技巧。

1.1 合理使用init.py文件

每个包的目录下面都有一个__init__.py文件,首先介绍一下什么是__init__.py文件以及它的功能。它是python中用于连接模块和包的连接文件,因而一般来说包(无论是顶层包还是子包)目录下都有这个文件(也有例外),在这个文件中包含可选的初始化代码。大多数情况下这个文件是空的,这是最最普通的情况,在这个文件中适当加上一些代码,会有一些意想不到的惊喜。

  • 1)第一种使用方法,在最开始的例子的subpjt1目录下的__init__.py文件中添加一下代码
from . import a
from . import b

这样用们就可以使用单独的import project.subpjt1语句就能直接导入a和b模块,而不需要分别导入

  • 2)第二种使用方法,加入__all__关键词,在最开始的例子的subpjt1目录下的__init__.py文件中添加一下代码
__all__ = ['a'] #只导入a,不导入b

当在使用__all__后,导入的时候只会导入包含在__all__中的模块,上例中就只会导入a模块,当试图在外部导入b模块的时候就会报错。同样也在以在模块中使用__all__关键词,这样该模块中只有包含在__all__中的方法和属性才能被调用。

注意事项: 在python3.3之后,就算不存在__init__.py文件也能够执行包的导入的操作。事实上,没有__init__.py文件的话创建的目录就是“命名空间包”,之后会介绍。

1.2 __all__ 搭配 import *控制对象的导入

当使用from module import *语句时,会把模块中不以下划线开头的对象全部导入(因为默认以下划线开头的对象都是属于私有的,不能被外部访问)。也就是说,如果定义了__all__,那么只有在__all__中列出来的方法和属性能调用。

def func_a():
    pass

def func_b():
    pass

def func_c():
    pass

__all__ = ['func_a','func_c']

在调用该模块的时候,只能调用func_a和func_c,不能调用func_b。在使用from module import *语句时,也只有func_a,func_c被调用。

1.3 使用相对名称调用子模块

在创建包的时候,经常会遇到模块之间相互调用的情况,这时候最好用的方法就是通过相对名称(也就是相对地址)调用模块。

/project
    /subpjt1
        __init__.py
        a.py
        b.py

    /subpjt2
        __init__.py
        c.py
        d.py
    __init__.py
test.py
  • 1)a调用b,也就是调用关系发生在同一目录,在文件a.py中加上
from . import b

同理,c中调用d from . import d

  • 2) a中调用c,也就是调用关系不发生在同一目录,在文件a.py中加上
from ..subpjt2 import c

同理,d中调用a:

from ..subpjt1 import a

以上发现:.表示当前目录 ..表示上一级目录。在包中调用的时候,一定使用这两个符号去检索,否则会容易出错,而且只能使用`from XX import module’ 这种表达,不能使用其他任何表达。

1.4 模块的分解

如果模块中功能太多而且有必要再分,这个时候可以将模块转换为包,也就是将.py文件拆分为一个目录,在这个目录下包含各种功能的模块。这种情况给引用带来麻烦。例如A是一个模块,调用A中的func时,只需要:import A.func, 如果转换为子包时,import A.module.func,也就是中间多了一层,这样的话代码不够简洁,此时我们需要在该子包的__init__.py文件中下功夫:

from .module1 import func1
from .module2 import func2

这样该子包的调用方式就和模块的调用方式一样了。再就是该子包在逻辑上成了一个单独的模块。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏calmound

JavaScript基础1

JavaScript写在<script></script>之间    <script type="text/javascript">表示在<script></s...

3216
来自专栏极乐技术社区

Belinda的小程序踩坑记(一)

微信小程序出来已有段时间,虽还在内测阶段。利用空闲时间,我把蜂贷微信项目部分迁移到小程序上。 目录结构 小程序的主体由三个文件组成,这三个文件要放在项目的根目录...

2027
来自专栏青枫的专栏

用gcc编译c语言程序以及其编译过程

对于初学c语言编程的我们来说,学会如何使用gcc编译器工具,对理解c语言的执行过程,加深对c语言的理解很重要!!!

621
来自专栏Zephery

Spring中Bean

一、什么是Bean 1、Java面向对象,对象有方法和属性,那么就需要对象实例来调用方法和属性(即实例化); 2、凡是有方法或属性的类都需要实例化,这样才能具象...

2776
来自专栏JavaEE

springboot中全局异常捕获类的写法

33512
来自专栏Java帮帮-微信公众号-技术文章全总结

hibernate延迟加载详解

hibernate延迟加载详解 Hibernae 的延迟加载是一个非常常用的技术,实体的集合属性默认会被延迟加载,实体所关联的实体默认也会被延迟加载。hiber...

2943
来自专栏从零开始学自动化测试

selenium+python自动化86-循环点击遇到的坑

# 前言 selenium定位一组元素,批量操作循环点击的时候会报错:Element not found in the cache - perhaps the ...

5104
来自专栏软件开发

CSS3与页面布局学习总结(二)——Box Model、边距折叠、内联与块标签、CSSReset

一、盒子模型(Box Model) 盒子模型也有人称为框模型,HTML中的多数元素都会在浏览器中生成一个矩形的区域,每个区域包含四个组成部分,从外向内依次是:外...

20610
来自专栏决胜机器学习

《Redis设计与实现》读书笔记(三十四) ——Redis Lua脚本环境设计与实现

《Redis设计与实现》读书笔记(三十四) ——Redis Lua脚本环境设计与实现 (原创内容,转载请注明来源,谢谢) 一、创建lua环境 为了在redis...

3525
来自专栏大前端_Web

NodeJS学习二CommonJS规范

Node程序由许多个模块组成,每个模块就是一个文件。Node模块采用了CommonJS规范。

742

扫码关注云+社区