Python中命名接口和抽象类的约定是什么?PEP 8没有讨论这个。例如,在 Java 中,接口通常以I
前缀命名。在 PHP(在命名空间之前)中,抽象类通常使用_Abstract
后缀命名。
(我意识到Pythonists并不热衷于接口,也许这就是我在这个话题上找不到太多共识的原因。但是接口和抽象类的使用不是我的问题。)
Python中命名接口和抽象类的约定是什么?PEP 8没有讨论这个。例如,在 Java 中,接口通常以I
前缀命名。在 PHP(在命名空间之前)中,抽象类通常使用_Abstract
后缀命名。
(我意识到Pythonists并不热衷于接口,也许这就是我在这个话题上找不到太多共识的原因。但是接口和抽象类的使用不是我的问题。)
除了PEP8之外,我不知道在这方面有任何社区范围的标准,它没有具体解决这个问题。
我建议做任何你的团队最舒服的事情,但最重要的是要保持一致。
我会查看数字塔(来自numbers
)、集合 ABC(来自collections.abc
)或其他核心 ABC(例如importlib.abc
),以获得最“Pythonic”的方式来执行此操作。
对此的共识是按原样命名它们,并让人类理解将它们识别为抽象的。
我认为用前缀命名接口I
是完全可以接受的。
例如:
IFoo
IPublishable
几年前,我使用了 Zope Interfaces。我注意到大多数代码库都使用这种约定。我们的团队也这样做了。
我们更喜欢IFoo
与FooInterface
或IFooInterface
如果您不关心类型提示,请随意命名它们。否则,ABC
s是您为其他开发人员提供的 API。他们的名字应该是干净的,没有任何杂乱。具体的实现应该会告诉你为什么它很特别。
打电话给你的班级User
,ServerUser
和LocalUser
第一个应该问自己的是,我们为什么要关心类的命名?
在静态类型语言(python 不是)中,您的接口名称代表一个 API,其他开发人员通过该 API 与您的代码进行交互。所以函数的调用者应该很快就能理解参数和返回类型的含义。Java 中的一个示例(其中前缀 Interfaces 前段时间已经过时..)将是:
public void signupUsers(Collection<User> users) {
// TODO: do something with users
}
在这里,我们希望名称尽可能纯净。我们接受任何Collection
和任何User
。它可能是ArrayList
,或HashSet
,我们不在乎。LocalUser
ServerUser
这与 python 无关,因为它是一种动态类型语言。在下面的代码中,你不需要关心类是如何被调用的:
def signup_users(users):
pass # TODO: do something with users
你只会在创建一个类并检查它的类型时才有意义,这不足以证明一个完整的命名约定是合理的
但是由于引入了类型模块,事情正在发生变化。您现在可以显式声明类型。如果我们想接受这个新特性,我们应该考虑类的命名。
按照与为什么其他语言放弃接口前缀的相同逻辑,我相信ABC
s(如果它们与接口起类似的作用)应该有一个干净的名称。like 的名称比 .User
好读得多IUser
。如果您有用户的具体实现,那么该实现的名称应该告诉您它有什么特别之处。是使用来自服务器的数据更新数据的用户吗?调用它ServerUser
。您是否在本地存储用户数据?调用它LocalUser
。
def signup_users(users: Iterable[User]) -> None:
pass # TODO: do something with users
关心实现细节的“丑陋”代码如下所示:
lovelace = LocalUser("Aida", "Lovelace", 1815)
babbage = ServerUser("htts://some_service.com/users/charles_babbage")
signup_users([aida, babbage])
这将处理复杂名称的负担放在必须处理实现的调用者身上——因为它应该