python - 如何构建面向对象的 Python 3 项目及其导入?
问题描述
我有一个面向对象的 Python 3.7 项目,其结构如下:
├── plugins
│ ├── book_management
│ │ ├── book_inserter.py
│ │ ├── book_remover.py
│ │ ├── __init__.py
│ │ ├── book.py
│ │ ├── book_sampler.py
│ │ ├── operators
│ │ │ ├── __init__.py
│ │ │ ├── register_book.py
│ │ │ ├── unregister_book.py
│ │ │ └── mark_book_as_missing.py
│ ├── __init__.py
│ ├── reader_management
│ │ ├── __init__.py
│ │ ├── reader.py
│ │ ├── reader_creator.py
│ │ ├── reader_emailer.py
│ │ ├── reader_remover.py
│ │ ├── operators
│ │ │ ├── __init__.py
│ │ │ ├── create_reader.py
│ │ │ ├── remove_reader.py
│ │ │ └── email_reader.py
├── tests
│ ├── __init__.py
│ ├── book_management_tests
│ │ ├── __init__.py
│ │ ├── test_book.py
│ │ ├── test_book_inserter.py
│ │ ├── test_book_remover.py
│ │ ├── test_book_sampler.py
│ │ ├── test_mark_book_as_missing_operator.py
│ │ ├── test_register_book_operator.py
│ │ ├── test_unregister_book_operator.py
│ ├── reader_management_tests
│ │ ├── __init__.py
│ │ ├── test_reader.py
│ │ ├── test_reader_creator.py
在像我这样的测试中,test_mark_book_as_missing_operator
我最终得到了如下的导入:
from plugins.book_management.book_inserter import BookInserter
from plugins.book_management.operators.mark_book_as_missing import (
MarkBookAsMissingOperator
)
from plugins.reader_management.reader_creator import ReaderCreator
from plugins.reader_management.operators.create_reader import (
CreateReaderOperator
)
拥有这些非常冗长的部分导入感觉真的很糟糕。所以我猜我一定做错了。理想情况下,导入plugins.reader_management
并plugins.reader_management.operators
可能更短一些似乎更具可读性。
book_inserter.py
正在定义一个类BookInserter
。理想情况下,我想保留这种 1-class / 1-file 结构。显然,这会导致文件数量的膨胀,但也允许更短更集中的文件。但是,如果这完全不是 Pythonic,我愿意听听为什么以及如何调整代码结构。
最后,我一直在使用这种多层架构(plugins/*_management/operators/*.py
),但这会导致很长的导入行,因此我经常遇到合法的 lint 问题。
我一直在考虑从顶级模块(如 book_management, in book_management/__init__.py
)导入子模块,但我不确定这是否是一种好习惯,而且这似乎违反了文件中没有未使用的导入的原则。(我也会因此面临循环进口的风险吗?)
简而言之,我的主要问题是:构建这样一个项目并设置导入的(?)Pythonic方式是什么(理想情况下,有一些理由说明为什么这将是一种/Pythonic方式)。
解决方案
使用它__init__.py
来压缩你的命名空间是非常好的。用于__all__
明确定义导入的名称用于导出。
# plugins/book_management/__init__.py
from .book_inserter import BookInserter
from .operators.mark_book_as_missing import MarkBookAsMissingOperator
# more imports
__all__ = [
'BookInserter',
'MarkBookAsMissingOperator',
# more exports
]
这减少了使用时导入的长度和数量:
# test_mark_book_as_missing_operator
from plugins.book_management import BookInserter, MarkBookAsMissingOperator
from plugins.reader_management import ReaderCreator, CreateReaderOperator
对于每个文件 1 个定义是否是一件坏事,似乎还没有达成共识。不过,对于标准库和许多第三方模块,习惯上将所有直接相关的类和函数放在一起。
推荐阅读
- php - 有没有办法让 PHP 在比较不同类型时产生警告?
- ios - 如何通过 Xcode 中的自定义框架访问 cocoapods
- selenium - 如何使用硒从可扩展部分中提取元素
- python - 如何设置 jupyter notebook 自动在浏览器上打开
- node.js - 快速服务器上的 RSS 订阅实现
- memory - 如何获取 WSL 进程的内存映射?
- java - 为什么 Jenkins 服务器上的“pitest-maven”构建项目没有加载“org.slf4j.impl.StaticLoggerBinder”类?
- python - 将 \n 添加到 __repr__
- search - 我的搜索按钮“未激活”并且无法工作,为什么?
- firebase - Firebase Cloud Functions 未记录,似乎未部署