return comments
comments = [
"Implementation note",
"Changed",
"ABC for generator",
]
print(" ".join(add_ellipsis(comments)))
# OUTPUT:
# Implementati...
# Changed
# ABC for gene...
add_ellipsis
函数接收一个列表作为参数,然后遍历它,替换掉需要修改的成员 。这一切看上去很合理,因为我们接到的最原始需求就是:“有一个列表,里面...” 。但如果有一天,我们拿到的评论不再是被继续装在列表里,而是在不可变的元组里呢?那样的话,现有的函数设计就会逼迫我们写出
add_ellipsis(list(comments))
这种即慢又难看的代码了 。面向容器接口编程我们需要改进函数来避免这个问题 。因为
add_ellipsis
函数强依赖了列表类型,所以当参数类型变为元组时,现在的函数就不再适用了(原因:给comments[index]
赋值的地方会抛出TypeError
异常) 。如何改善这部分的设计?秘诀就是:让函数依赖“可迭代对象”这个抽象概念,而非实体列表类型 。使用生成器特性,函数可以被改成这样:
【Python 容器使用的 5 个技巧和 2 个误区】
-
def add_ellipsis_gen(comments: typing.Iterable[str], max_length: int = 12):
-
"""如果可迭代评论里的内容超过 max_length,剩下的字符用省略号代替
-
"""
-
for comment in comments:
-
comment = comment.strip
-
if len(comment) > max_length:
-
yield comment[:max_length] + '...'
-
else:
-
yield comment
-
print(" ".join(add_ellipsis_gen(comments)))
-
# 处理放在元组里的评论
-
comments = ("Implementation note", "Changed", "ABC for generator")
-
print(" ".join(add_ellipsis_gen(comments)))
-
# 处理放在文件里的评论
-
with open("comments") as fp:
-
for comment in add_ellipsis_gen(fp):
-
print(comment)
答案是:各个容器类型实现的接口协议定义了容器 。不同的容器类型在我们的眼里,应该是
是否可以迭代
、是否可以修改
、有没有长度
等各种特性的组合 。我们需要在编写相关代码时,更多的关注容器的抽象属性,而非容器类型本身,这样可以帮助我们写出更优雅、扩展性更好的代码 。Hint:在 itertools 内置模块里可以找到更多关于处理可迭代对象的宝藏 。
常用技巧1. 使用元组改善分支代码有时,我们的代码里会出现超过三个分支的
if/else
。就像下面这样:-
import time
-
def from_now(ts):
-
"""接收一个过去的时间戳,返回距离当前时间的相对时间文字描述
-
"""
-
now = time.time
-
seconds_delta = int(now - ts)
-
if seconds_delta < 1:
-
return "less than 1 second ago"
-
elif seconds_delta < 60:
-
return "{} seconds ago".format(seconds_delta)
-
elif seconds_delta < 3600:
-
return "{} minutes ago".format(seconds_delta // 60)
推荐阅读
- MySQL的查询性能分析神器:explain命令的使用详解
- Python爬虫:scrapy之Cookie和Session
- Python中的高阶函数
- 国内顶尖大佬整理的Python入门教程完整版!懂中文就能学会
- 一文看懂Python变量和赋值语句
- 在Python中定义Main函数
- 红衣天使怎么养 小红衣怎么养
- 怎样正确使用阿司匹林
- 买房为什么要交公共维修基金?什么情况下使用公共维修基金……
- 医保卡使用有技巧,做对这几件事报销的更多