page contents

Python教程:Python 包和模块使用注意事项

今天这个专题讨论Python代码工程化、结构化的方法.我们都会遇到这种情景:所有代码都堆积到一个模块里,导致代码越来越长,最后变得难以维护,很明显代码只写到一个py模块文件是不可取的.如何按照逻辑功能,将代码划分到不同模块,组织为一个更易读、更易维护的代码结构呢?

attachments-2024-07-rY6Pmf6E66a4615ef00d3.jpg今天这个专题讨论Python代码工程化、结构化的方法.我们都会遇到这种情景:所有代码都堆积到一个模块里,导致代码越来越长,最后变得难以维护,很明显代码只写到一个py模块文件是不可取的.如何按照逻辑功能,将代码划分到不同模块,组织为一个更易读、更易维护的代码结构呢? 

1 包和模块的定义

包(package)是一个文件夹,它里面会有一个__init__.py,还有我们自己定义的.py文件.

而我们自己定义的.py文件,python中称为模块(module),一个模块就是一个py文件,里面封装了一个功能模块,可能有函数、类、变量等.

如下建立的一个代码结构:

classdemo/

├── animals

│   ├── animal2.py

│   ├── animal.py

│   ├── __init__.py

│   ├── manager2.py

│   └── manager.py

└── search

    ├── binarytree_level.py

    └── __init__.py

里面包括两个package,一个为animals包,另一个为search包. 每个package里都有一个__init__.py文件.

使用这种结构带来什么便利?每个模块间的变量又该如何引用?里面的__init__.py起到什么作用?下面一一解答.

2 解决变量命名冲突

对程序员而言,变量命名往往是一个很头疼的难题,并且一不小心就会写出名称相同的变量,尤其是在同一模块里变量名称重复会很麻烦.

通常来说,一个模块里定义的代码行数不要太多,尽量拆分到不同的模块里,不同的模块允许出现相同名称的变量,这是划分不同模块的作用之一.

但是仅有模块好像还不够,对于一个大点的框架,再按照大的功能逻辑划分出包(package)显得更有必要.

并且有了package后,相同变量名字冲突的可能性会更小.如第1小节中的Animal类,它的完整名称实际为:animals.animal2.Animal,这样在使用Animal等类时,导入方法是下面这样:

from animals.animal2 import (Animal2,Cat,Bird)

实际上,这种层级的组织在一些大的框架中到处可见.

3 __init__.py 作用

如上所述,__init__.py会使得普通的文件夹变为package. 实际上,__init__.py也是一个模块,其名称正是package的名字.

一般来说此文件为空,如下导入animals包:

In [2]: import animals                                                                              

In [3]: animals                                                                                       

Out[3]: <module 'animals' from '/home/zglg/mywork/mdfiles/

classdemo/animals/__init__.py'

可以看到导入animals包实际上导入了它下面的__init__.py文件.

同时还可以为它增加其他功能.

因为在导入一个包时实际上导入它的__init__.py文件,利用此特性,可以在__init__.py文件中批量导入多个模块都在公用的模块,而不再需要一个一个的导入.

拿上面的demo来说,manager.py和manager2.py中都用到time模块,我们就其移动到__init__.py里:

# __init__.py

import time

import os

import sys

import abc

在使用这些内置等模块时,首先导入包:

import animals # 导入包

在调用time模块时,必须使用包名+模块名的方式引用:

def recordTime(self):

        #引用变为:包名animals + 模块名称

        self.__t = animals.time.time() 

        print('feeding time for %s is %.0f'%(self.animal.name,self.__t))

        self.animal.getSpeedBehavior()

4 解决找不到模块的问题

我们知道Python中使用import导入需要的包,然而平时使用像vscode, pycharm这列ide时,经常出现找不到包的问题,错误信息如下:

Exception has occurred: ModuleNotFoundError

No module named 'animals'

要想解决此问题,需要首先了解Python的import机制.

当导入模块时,解释器会按照sys.path列表中的目录顺序来查找导入文件.要想查看解释器目前查找的目录顺序,先导入通过sys模块,使用sys.path,如下是import时查看的目录顺序:

['/home/zglg/mywork/md...mo/animals',

'/home/zglg/anaconda3...thon37.zip',

'/home/zglg/anaconda3.../python3.7',

'/home/zglg/anaconda3...ib-dynload',

'/home/zglg/anaconda3...e-packages']

看到animals包不在解释器要查找的目录里,所以出错了.

所以需添加animals包所在的文件夹路径,其中一种修改方法如下,直接粗暴向sys.path中添加找不到的目录:

# 调整为根目录(调用dirname一次获得其所在文件夹) 

# 就当前文件目录,我们两次便定位到根目录 classdemo

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  

# __file__获取执行文件相对路径,整行为取上一级的上一级目录

sys.path.append(BASE_DIR)

import animals

再次启动程序,看到animals包目录已经显示搜索path列表中:

['/home/zglg/mywork/mdfiles/classdemo',

'/home/zglg/mywork/md...mo/animals',

'/home/zglg/anaconda3...thon37.zip',

'/home/zglg/anaconda3.../python3.7',

'/home/zglg/anaconda3...ib-dynload',

'/home/zglg/anaconda3...e-packages']

接下来就可以正常导入animals包,找不到包的问题解决.

以上就是此专题介绍的Python包、模块概念,以及如何应用到我们自己的实际项目的代码框架中,写出更加容易维护、可读性更好的代码.

更多相关技术内容咨询欢迎前往并持续关注好学星城论坛了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

  • 发表于 2024-07-27 10:54
  • 阅读 ( 68 )
  • 分类:Python开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
小柒
小柒

1478 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1478 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章