days如今,人们经常对OO进行抨击,至少在Python中,我越来越认为他们是正确的。我在这里的观点并不是要论证OO本质上是不好的,更多的是它的引入根本没有必要,AKA也没有用。
可以将所有OO代码重构为等效的非OO代码,这些代码非常容易理解。
让我们以应该在OO中获得成功的示例为例,我们已经看到/编写了一些类似于以下内容的代码:
类ApiClient:def __init __(self,root_url:str,session_cls:sessionmaker):self.root_url = root_url self.session_cls = session_cls def Construct_url(self,实体:str)-> str:返回f" {self.root_url} / v1 / {entity}" def get_items(self,entity:str)-> List [Item]:resp = request.get(self.construct_url(entity))resp.raise_for_status()返回[resp.json()中n的Item(** n)[" items"]] def save_items(self,entity:str)->无:以scoped_session(self.session_cls)作为会话:session.add(self.get_items(entity))class ClientA(ApiClient):def Constructor_url(self,entity:str)-> str:返回f" {self.root_url} / {entity}"类ClientB(ApiClient):def Construct_url(自身,实体:str)-> str:返回f" {self.root_url} / a / special / place / {entity}" client_a = ClientA(" https:// client-a&#34 ;, session_cls)client_a.save_items ("酒吧")
我们之所以选择OO,是因为我们想将root_url绑定到某些东西,并且我们不想传递sessionmaker。我们还想利用继承在调用堆栈中途插入方法。
但是,如果我们只是传递数据并编写“无聊”怎么办?函数,然后会发生什么?
@dataclassclass客户端:root_url:str url_layout:strclient_a =客户端(root_url =" https:// client-a&#34 ;, url_layout =" {root_url} / {entity}",)client_b =客户端(root_url =" https:// client-b&#34 ;、 url_layout =" {root_url} / a / special / place / {entity}")def Construct_url(client:客户,实体:str)-> str:返回client.url_layout.format(root_url = client.root_url,entity = entity)def get_items(client:Client,entity:str)-> List [Item]:resp = request.get(construct_url(client,entity))resp.raise_for_status()返回[resp.json()中n的Item(** n)[" items"]] def save_items(客户端:客户端,session_cls:session_cls,实体:str)->无:使用scoped_session(session_cls)作为会话:session.add(get_items(client,entity))save_items(client_a,session_cls," bars")
谁在乎?我们甚至少写了10%的字符。而且,根据推测,生成的代码至少很容易理解,我们不需要任何面向对象。
我听说过这种称为功能袋风格的风格。也就是说,您的所有代码仅由类型化数据和模块命名功能包组成。
只要尝试在没有它们的情况下书写,我保证一切都会好起来的。 (为公平起见,这只是向Python引入了类型提示,使功能包风格如此令人愉悦)。
如果您服用了纯FP /六边形体系结构药丸,那么您想编写采用不纯的适配器的纯类。获取当前日期时间/ API调用/与数据库通话/其他不纯净的东西的实例。这个想法原则上很好-应该适合测试吗? -在实践中,您可以只使用freezegun /使用响应/对数据库进行测试(其他不纯净的东西实际上并不存在)并为自己省去很多麻烦。
您会注意到我在重构代码中放入了@dataclasss,它们很好-它们只是记录类型。 Python 5将仅具有这些,而不会与' normal'类。
可以将Exception子类化。 try:...的用法除了SomeClass:...从根本上将您与一个分层的世界观联系在一起,这很好,只是请不要使其变得过于复杂。
非常非常偶尔(至少在应用程序开发中),您会想到一个经常使用的核心类型,很高兴拥有可爱的东西-想像pandas.DataFrame / sqlalchemy之类的东西。会议。总的来说,不要自欺欺人,以为自己正在建造令人兴奋的东西,只是虚荣才能使自己变得更好。
好的,我撒谎了,这不仅是因为OO在很大程度上没有用到该语言,而且还常常掩盖了手头的问题并鼓励不良行为: 它鼓励您变异。 功能袋使更改参数感到讨厌-就像应该感觉到的那样。 (请随时在您的功能BTW范围内进行更改,不要生气FP)。 它只是全局变量的返回。 无法通过自已在函数之间共享数据会迫使您编写状态空间较小且易于测试的函数。 将数据与函数配合使用会增加序列化的难度,在REST API的世界中,序列化非常有用。 不过,最重要的是,它什么也没添加,只是杂乱无章的事情分散了眼前的问题,使导航/理解您的代码变得更加困难。