Python 包、模块、类以及代码文件和目录的一种管理方案
admin
2023-07-31 00:46:49
0

1.要解决的问题

Python在语义中存在着模块(当然还有函数)这几个概念。

在编写Python代码时,我们需要管理代码的文件目录结构

这时候会遇到这样一种情况:

1.由于Python一个文件一个模块一个带__init__.py的目录算一个

2.而为了控制代码文件不要过大,我们需要的是一个类(几个类或加些许函数)分配一个文件

3.这时候会出现类似这样的语句:

123456789 #第一种import package_a.class_a_file as cafa = caf.ClassA() #第二种form package_a.class_a_file import *a = ClassA() #另外几种就不意义列举了…

以上除了直观上可以看出import过长外,隐藏的另一点是我们是希望一个类一个文件,在使用多个相关类的时候就必须写很多import。(注:我们可不想一堆代码扎堆,弄出一个超大代码文件。)

2.解决方案要达到的效果

12345678910111213 #文件目录结构#|–demo.py#|–package_a#   |–__init__.py#   |–class_a.py  #类ClassA#   |–class_b.py  #类ClassB和函数func_b() #demo.py中可以直接使用from package_a import * a = ClassA()b = ClassB()func_b()

由于Python里一个带__init__.py的目录算一个包,所以利用这一机制,把类文件放在包里,用包来管理类。

注:在Python里“包是模块,而模块不是包”。用system.modules可以取到的名字是包和模块都有的,而用__package__却能很好的区分包和模块。也就是“包其实是一种特殊的模块”。

3.解决方案

这就是解决方案的文件base.py,代码很短:

12345678910111213141516171819202122232425 import sys _packet_ = {} #它是个装饰器,item是类,或者函数def export(item):    #获取item的模块对象    module = sys.modules[item.__module__]    #由模块对象得到包对象    package = sys.modules[module.__package__]    #把item添加到包的__dict__里    package.__dict__[item.__name__] = item    #生成所有使用该解决方案的包的__all__变量,并把导出的item添加进去    if not package.__name__ in _packet_:        _packet_[package.__name__] = []    _packet_[package.__name__].append(item.__name__)    #原封不动地把item返回    return item #它是个函数,在包__init__.py里用于获取__all__def packet(name):    if not name in _packet_:        _packet_[name] = []    return _packet_[name] 

代码用意我写在注释里了,就是以装饰器来把类添加到包的__dict__和__all__里。__all__需要利用packet在包里生成,不这么做只会使得from package_name import * 后不能找到类,需要写具体的类名from package_name import ClassA。

4.使用解决方案

先来看下使用解决方案后的目录结构:

1234567 #文件目录结构(使用后结构只多了base.py)#|–base.py#|–demo.py#|–package_a#   |–__init__.py#   |–class_a.py  #类ClassA#   |–class_b.py  #类ClassB和函数func_b()

代码处就需要做到以下几点:

1.关于被导出的类文件里应该怎么做,这里以class_b.py为例子:

12345678910111213 # ./package_a/class_b.py #1.需要导入baseimport base #2.使用export装饰器,装饰要导出的类或函数@base.exportclass ClassB:pass #2.同样的export可以导出函数@base.exportdef func_b():    print(\’func_b\’)

2.使用了导出功能的包要做什么,这里以package_a包为例:

12345678910111213141516 # ./package_a/__init__.py #1.导入baseimport base #2.导入将要导出的子模块,需要具体模块名字的形式,from . import * 不可用from . import class_a,class_b #3.用packet初始化__all__,这个可选,主要是看要不要支持 from 的用 * 导入__all__ = base.packet(__name__) #4.这个是可选的,因为如果用了__all__会影响from *。可以用export把__init__.py里的项,加入__all__@base.exportdef pafunc():    print(\’pafunc\’) 

5.总结

使用该解决方案可以归纳为两点:

1.用@base.export标记要导出的类或函数

2.在包__init__.py里初始化__all__ = base.packet(__name__)

3.(说好的只有两点呢?)其实第2点是可选的,不过最好加上。而在包的__init__.py里导入子模块才是真正的第2点。不然子模块不会被载入,也谈不上导出了。

最后,demo.py里可以这么写,和预期的效果一样:)

12345678 # ./demo.py from package_a import * a = ClassA() # 上面的实例没有给出,不过假设有ClassA在class_a.py里的b = ClassB()func_b() 


相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
python清除字符串里非数字... 本文实例讲述了python清除字符串里非数字字符的方法。分享给大家供大家参考。具体如下: impor...