python - 如何组织 Python API 模块使其整洁?
问题描述
我正在编写一个代表一些 Web API 的 Python 库。现在,我的库目录看起来接近这个:
__init__.py
Account.py
Order.py
Category.py
requests.py
在__init__.py
,我有这样的事情:
from .Account import Account
from .Order import Order
from .Category import Category
from . import requests
这允许使用import cool_site
然后cool_site.Account(…)
等等,但它有以下问题:当我在 IDLE 中玩弄我的代码时,对象然后被调用cool_site.Account.Account
,我觉得这很糟糕。
1.有什么办法可以避免类名重复,并且每个类都有单独的文件吗?
下一件我感觉不太好的事情是我的代码组织。现在,我的Account
班级在初始化时获取凭据,创建一个requests.Session
对象,然后处理与服务器的所有通信,即搜索订单等。然后,此类Account
实例会将自身传递给所有其他实例,例如传递给Order
- 因此订单的实例将具有.account
保存Account
创建它的实例的属性。当另一个类实例本身必须做某事时,例如更改订单的注释(通过调用o.comment = 'new comment'
,因此通过类@comment.setter
中的装饰器Order
),它会将其转发给在初始化时传递给它的 Account 对象,然后使用 example self.account.set_order_comment(new_comment)
。然后,此方法将使用所有 Web 请求来实现该目标。
2. 将服务器通信逻辑放在一个类中更好还是将其不同方面分散到受它们影响的类中更好?
我想问的最后一件事是如何以及在何处保留低级请求模板。现在我在cool_site.requests
子模块中有它,并且对于不同的请求有不同的功能,例如SetOrderComment
对于上面提到的情况(它是一个函数,所以它应该是小写的,但在这种情况下,我认为它在某种程度上类似于一个类 - 是可以吗?)。将Account.set_order_comment
像这样使用它:
r = cool_site.requests.SetOrderComment(order.id, new_comment)
response = self._session.request(**r)
Session.request
因为这个函数从requests
库返回一个带有参数的字典。身份验证标头已在类实例的_session
属性中设置。Account
我觉得它有点难看,但我没有更好的主意。
3.如何组织网络请求以保持一切干净?
后文
很抱歉这个问题太长了,涵盖了 API 库设计的许多方面,但所有的提示都将不胜感激。在某种程度上,以上三个问题都可以表达为“如何做得更好、更清洁?” 或“大多数 Python 开发人员是如何做到的?”,甚至可能是“最 Pythonic 的感觉是什么?”。
把你能想到的任何小技巧都扔给我。
解决方案
我最近一直在考虑非常相似的事情wistiapy
。我目前对客户端代码组织的思考的例子就在里面。YMMV。
“每个文件一个类”比 Python 更像是一种 Java 风格指南。Python 模块是代码层次结构中合法且重要的级别,您不必担心同一模块中有多个函数或类。您可以将所有模型类放在一个
.models
模块中,然后from .models import (Account, Order, Category)
在__init__.py
.客户端库的或多或少的常见做法似乎是有一个
client
模块,包含类似MyServiceClient
类的东西。(例如Segment 客户端)。这就是网络逻辑的所在。如果您想让公共接口成为模块级函数,您可以通过创建默认客户端并让函数调用其方法来做一些聪明的事情。
函数应该是snake_case
,类应该是PascalCase
。做任何其他事情往往会导致更多的混乱而不是好处。
您正在处理的一个大问题似乎是试图在“Active Record”模式(some_account.set_order_comment(comment)
)和“Data Mapper”模式(set_order_comment(account, comment)
)之间进行选择。两者都可以,它们各有优缺点。我发现数据映射器模式——使用智能函数来操作相当简单的数据类——更容易开始。
我发现同时设计公共接口和使用该接口的东西很有帮助。在调用代码中,您可以编写您想调用的内容,然后“由外向内”实现客户端代码。
推荐阅读
- sql - 从四个表中整理数据的问题
- reactjs - 在 React 中创建 FullCalendar 自定义按钮
- c++ - 在 Macbook Pro 上实现 clang -fno-stack-protector 来编译代码的问题
- python - 遍历字典时缺少键
- android - 重新发布被拒绝的android应用程序的正确方法
- kendo-ui - 剑道甘特图中的里程碑渲染
- google-cloud-storage - 如何等待 gcsfuse 写入(刷新)到 GCS 存储桶?
- c++ - 我可以在不同的 TU 中提供相同的函数定义吗
- python - 如何在 Django REST 框架中执行更新、删除操作
- google-chrome-extension - 如何将生成的用户 ID 传递到 chrome 扩展的搜索 URL?