首页 > 解决方案 > 如何组织 Python API 模块使其整洁?

问题描述

我正在编写一个代表一些 Web API 的 Python 库。现在,我的库目录看起来接近这个:

__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 的感觉是什么?”。

把你能想到的任何小技巧都扔给我。

标签: pythonapi-designusabilityreadabilitycode-organization

解决方案


我最近一直在考虑非常相似的事情wistiapy。我目前对客户端代码组织的思考的例子就在里面。YMMV。

  1. “每个文件一个类”比 Python 更像是一种 Java 风格指南。Python 模块是代码层次结构中合法且重要的级别,您不必担心同一模块中有多个函数或类。您可以将所有模型类放在一个.models模块中,然后from .models import (Account, Order, Category)__init__.py.

  2. 客户端库的或多或少的常见做法似乎是有一个client模块,包含类似MyServiceClient类的东西。(例如Segment 客户端)。这就是网络逻辑的所在。如果您想让公共接口成为模块级函数,您可以通过创建默认客户端并让函数调用其方法来做一些聪明的事情。

函数应该是snake_case,类应该是PascalCase。做任何其他事情往往会导致更多的混乱而不是好处。

您正在处理的一个大问题似乎是试图在“Active Record”模式(some_account.set_order_comment(comment))和“Data Mapper”模式(set_order_comment(account, comment))之间进行选择。两者都可以,它们各有优缺点。我发现数据映射器模式——使用智能函数来操作相当简单的数据类——更容易开始。

我发现同时设计公共接口和使用该接口的东西很有帮助。在调用代码中,您可以编写您想调用的内容,然后“由外向内”实现客户端代码。


推荐阅读