写在前面
最近在帮朋友写个敏感信息提取的工具,因为涉及文件类型过多,我想写成一个可扩展的框架出来,方便往里面添加自定义的插件,在封装自建包的时候,踩到了一个很低级的坑,记录一下。
问题现象
我封装了一个包名为FileChecker的包,目录结构如下
├─FileChecker
│ │ FileCheckerBase.py
│ │ SensitiveCheck.py
│ │ TxtFileChecker.py
│
│ main.py
其中FileCheckerBase.py的内容如下
from abc import ABC, abstractmethod
class FileCheckerBase(ABC):
...
TxtFileChecker.py的内容如下
from .FileCheckerBase import FileCheckerBase
class TxtFileChecker(FileCheckerBase):
...
FileCheckerBase.py中存放了FileCheckerBase类
而TxtFileChecker.py中存放了TxtFileChecker类,继承了FileCheckerBase类
坑这就来了,我在根目录的main.py文件下对FileChecker包进行如下调用
from FileChecker import FileCheckerBase, TxtFileChecker
只放这一句就够了,不知道大家发现问题了没有,当时我是没发现
在对TxtFileChecker进行实例化的时候,报错了
'TxtFileChecker' object is not callable
说TxtFileChecker不是一个可被调用的对象
当时当局者迷,百思不得其解
改BUG
经过一番排查,大家还记得目录结构吗
├─FileChecker
│ │ FileCheckerBase.py
│ │ SensitiveCheck.py
│ │ TxtFileChecker.py
│
│ main.py
我在main函数中的调用
from FileChecker import FileCheckerBase, TxtFileChecker
对照一看发现,突然惊醒
我import进来的是FileCheckerBase.py和TxtFileChker.py这俩文件,而不是里面的类
方案一
正确写法应该是
from FileChecker.FileCheckerBase import FileCheckerBase
from FileChecker.TxtFileChecker import TxtFileChecker
虽然这样解决了问题,但是我还是不满足,毕竟这么写还是有点麻烦,我每个插件难道都要这么调用吗?
方案二
于是乎,我用到了__init__.py文件,在调包的时候会率先调用包下的__init__.py文件,跟实例化类的时候类似
此时目录结构如下
├─FileChecker
│ │ FileCheckerBase.py
│ │ SensitiveCheck.py
│ │ TxtFileChecker.py
│ │ __init__.py
│
│ main.py
__init__.py内容如下
from .FileCheckerBase import FileCheckerBase
from .TxtFileChecker import TxtFileChecker
__all__ = [
FileCheckerBase,
TxtFileChecker
]
通过配置__all__,来让FileChecker这个包只导出__all__中所添加的内容
此时,我便可以直接通过FileChecker来调用FileCheckerBase和TxtFileChecker
from FileChecker import FileCheckerBase, TxtFileChecker
这个时候这样写也是可以正常使用的
感觉这个坑和拼写错误有得一拼(捂脸)
END
原文始发于微信公众号(飞羽技术工坊):封装Python包时的乌龙(和拼写错误有得一拼)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论