Python中的字符串是否应该可迭代?

Guido在C的图像中创建了字符串,在字符数组的图像中创建了它们。 Guido认为这很好。 还是不行

想象一下,您正在编写完全惯用的代码,以绕过嵌套的某些数据。 美丽胜于丑陋,简单胜于复杂,因此您停止使用以下版本的代码:

from collections.abc import Iterable def traverse(list_or_value, callback): if isinstance(list_or_value, Iterable): for item in list_or_value: traverse(item, callback) else: callback(list_or_value) 

您编写一个单元测试,您会怎么想? 它不起作用,不仅不起作用,而且

 >>> traverse({"status": "ok"}, print) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in traverse File "<stdin>", line 4, in traverse File "<stdin>", line 4, in traverse [Previous line repeated 989 more times] File "<stdin>", line 2, in traverse File "/usr/local/opt/python/libexec/bin/../../Frameworks/Python.framework/Versions/3.7/lib/python3.7/abc.py", line 139, in __instancecheck__ return _abc_instancecheck(cls, instance) RecursionError: maximum recursion depth exceeded in comparison 

怎么了 怎么了 在寻找答案时,您将陷入无限深度的奇妙世界。

实际上,字符串是唯一始终将Iterable作为元素返回的内置Iterable ! 当然,我们可以通过创建一个列表并将其添加一次或两次来构造另一个示例,但是您是否经常在代码中看到这一点? 该生产线具有无限深度的可Iterable ,可以在夜幕掩护下潜入您的生产中。

另一个例子。 在代码中的某个位置,您需要重复检查容器中元素的存在。 您决定编写一个以多种方式加速它的助手。 您编写了一个仅使用__contains__方法( Container的抽象Base类中的唯一方法)的通用解决方案,但是随后您决定为特殊情况(集合)添加超优化。 毕竟,您可以沿着它走一圈,然后set一个!

 import functools from typing import Collection, Container def faster_container(c: Container) -> Container: if isinstance(c, Collection): return set(c) return CachedContainer(c) class CachedContainer(object): def __init__(self, c: Container): self._contains = functools.lru_cache()(c.__contains__) def __contains__(self, stuff): return self._contains(stuff) 

III ...您的解决方案不起作用! 好吧! 再来一次!

 >>> c = faster_container(othello_text) >>> "Have you pray'd to-night, Desdemona?" in c False 

(但是错误答案很快就发出了……)

怎么了 因为Python中的字符串是一个了不起的集合,其中__contains__方法的语义与__iter____len__的语义不一致

实际上,字符串是一个集合:

 >>> from collections.abc import Collection >>> issubclass(str, Collection) True 

但是收集...什么? __iter____len__认为这是字符的集合:

 >>> s = "foo" >>> len(s) 3 >>> list(s) ['f', 'o', 'o'] 

但是__contains__认为这是子字符串的集合!

 >>> "oo" in s True >>> "oo" in list(s) False 

该怎么办?


尽管在其他标准类型的__contains__实现的上下文中, str.__contains__的行为似乎很奇怪,但这种行为是使Python像脚本语言一样方便的许多小事情之一。 允许您在上面编写快速的文字代码。 我不建议更改此方法的行为,尤其是因为我们几乎从不使用它来检查字符串中是否存在单个字符。

顺便说一句,你知道为什么吗? 因为我们几乎从不使用字符串作为脚本语言中的字符集合! 操纵字符串中的特定字符,通过索引进行访问-通常是访谈中任务的命运。 因此,也许您应该从字符串中删除__iter__ ,将其隐藏在.chars()类的方法后面? 这将解决这两个问题。

在评论中进行周五讨论的时间!

Source: https://habr.com/ru/post/zh-CN451252/


All Articles