本文共 3308 字,大约阅读时间需要 11 分钟。
????点击上方蓝字“Python猫”,免费获得一个公众号花下猫语:今天继续给大家分享一篇好文章,有助于 Python 进阶的。Python 是一门支持面向对象的语言,但它跟典型的面向对象语言不完全相同。如何在 Python 中写出良好的面向对象代码呢?全文较长,建议收藏后慢慢阅读。
图 | 宫崎骏电影《侧耳倾听》
作者:piglei | 公众号:piglei
(本文经原作者授权转载,不得二次转载)
前言这是 “Python 工匠”系列的第 12 篇文章。
全系列地址:https://github.com/piglei/one-python-craftsman
Python 是一门支持多种编程风格的语言,面对相同的需求,拥有不同背景的程序员可能会写出风格迥异的 Python 代码。比如一位习惯编写 C 语言的程序员,通常会定义一大堆函数来搞定所有事情,这是“过程式编程”的思想。而一位有 Java 背景的程序员则更倾向于设计许多个相互关联的类(class),这是 “面向对象编程(后简称 OOP)”。
虽然不同的编程风格各有特点,无法直接比较。但是 OOP 思想在现代软件开发中起到的重要作用应该是毋庸置疑的。
很多人在学习如何写好 OOP 代码时,会选择从那 23 种经典的“设计模式”开始。不过对于 Python 程序员来说,我认为这并非是一个最佳选择。
Python 对 OOP 的支持
Python 语言虽然拥有类、继承、多态等核心 OOP 特性,但和那些完全基于 OOP 思想设计的编程语言(比如 Java)相比,它在 OOP 支持方面做了很多简化工作。比如它 没有严格的类私有成员,没有接口(Interface)对象 等。
而与此同时,Python 灵活的函数对象、鸭子类型等许多动态特性又让一些在其他语言中很难做到的事情变得非常简单。这些语言间的差异共同导致了一个结果:很多经典的设计模式到了 Python 里,就丢失了那个“味道”,实用性也大打折扣。
拿大家最熟悉的单例模式来说。你可以花上一大把时间,来学习如何在 Python 中利用 __new__ 方法或元类(metaclass)来实现单例设计模式,但最后你会发现,自己 95% 的需求都可以通过直接定义一个模块级全局变量来搞定。
所以,与具体化的 设计模式 相比,我觉得一些更为抽象的 设计原则 适用性更广、更适合运用到 Python 开发工作中。而谈到关于 OOP 的设计原则,“SOLID” 是众多原则中最有名的一个。
SOLID 设计原则
著名的设计模式书籍《设计模式:可复用面向对象软件的基础》出版于 1994 年,距今已有超过 25 年的历史。而这篇文章的主角:“SOLID 设计原则”同样也并不年轻。
早在 2000 年,Robert C. Martin 就在他的文章 "Design Principles and Design Patterns" 中整理并提出了 “SOLID” 设计原则的雏型,之后又在他的经典著作《敏捷软件开发 : 原则、模式与实践》中将其发扬光大。“SOLID” 由 5 个单词组合的首字母缩写组成,分别代表 5 条不同的面向对象领域的设计原则。
在编写 OOP 代码时,如果遵循这 5 条设计原则,就更可能写出可扩展、易于修改的代码。相反,如果不断违反其中的一条或多条原则,那么很快你的代码就会变得不可扩展、难以维护。
接下来,让我用一个真实的 Python 代码样例来分别向你诠释这 5 条设计原则。写在最前面的注意事项:“原则”不是“法律”,它只起到指导作用,并非不可以违反
“原则”的后两条与接口(Interface)有关,而 Python 没有接口,所以对这部分的诠释是我的个人理解,与原版可能略有出入
文章后面的内容含有大量代码,请做好心理准备 ☕️
为了增强代码的说明性,本文中的代码使用了 Python3 中的 类型注解特性
SOLID 原则与 Python
Hacker News(后简称 HN) 是一个在程序员圈子里很受欢迎的站点。在它的首页,有很多由用户提交后基于推荐算法排序的科技相关内容。
我经常会去上面看一些热门文章,但我觉得每次打开浏览器访问有点麻烦。所以,我准备编写一个脚本,自动抓取 HN 首页 Top5 的新闻标题与链接,并用纯文本的方式写入到文件。方便自己用其他工具阅读。
图:Hacker News 首页截图
编写爬虫几乎是 Python 天生的拿手好戏。利用 requests、lxml 等模块提供的好用功能,我可以轻松实现上面的需求。下面是我第一次编写好的代码:importio
importsys
fromtypingimportGenerator
importrequests
fromlxmlimportetree
classPost:
"""HN(https://news.ycombinator.com/) 上的条目
:param title: 标题
:param link: 链接
:param points: 当前得分
:param comments_cnt: 评论数
"""
def__init__(self, title: str, link: str, points: str, comments_cnt: str):
self.title = title
self.link = link
self.points = int(points)
self.comments_cnt = int(comments_cnt)
classHNTopPostsSpider:
"""抓取 HackerNews Top 内容条目
:param fp: 存储抓取结果的目标文件对象
:param limit: 限制条目数,默认为 5
"""
ITEMS_URL ='https://news.ycombinator.com/'
FILE_TITLE ='Top news on HN'
def__init__(self, fp: io.TextIOBase, limit: int =5):
self.fp = fp
self.limit = limit
deffetch(self) ->Generator[Post,None,None]:
"""从 HN 抓取 Top 内容
"""
resp = requests.get(self.ITEMS_URL)
# 使用 XPath 可以方便的从页面解析出你需要的内容,以下均为页面解析代码
# 如果你对 xpath 不熟悉,可以忽略这些代码,直接跳到 yield Post() 部分
html = etree.HTML(resp.text)
items = html.xpath('//table[@class="itemlist"]/tr[@class="athing"]')
foriteminitems[:self.limit]:
node_title = item.xpath('./td[@class="title"]/a')[0]
node_detail = item.getnext()
points_text = node_detail.xpath('.//span[@class="score"]/text()')
comments_text = node_detail.xpath('.//td/a[last()]/text()')[0]
yieldPost(
title=node_title.text,
link=node_title.get('href'),
# 条目可能会没有评分
points=points_text[0].split()[0]ifpoints_textelse'0',
comments_cnt=comments_text.split()[0]
)
defwrite_to_file(self):
"""以纯文本格式将 Top 内容写入文件
"""
转载地址:https://blog.csdn.net/weixin_39767645/article/details/110751746 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!