为什么我不能将 join 用于实现 __str__ 的对象列表?

Why I can't use join for a list of objects that implement __str__?

我正在研究Python中的duck typing,我知道如果你为一个class实现一些特殊的方法,你可以愉快地使用内置的class方法

例如:

class A:
    def __init__(self,l):
        self._l = l
    def __iter__(self):
        return iter(self._l)

如果我这样做,我可以使用 for...in..,zip,以及其他一些内置的方法,也可以做一些其他的事情,比如实现 __setitem__(),所以我可以使用 random.choice,random.shuffle,我觉得python很酷,但是后来我发现这个问题,我想用join来打印一些我实现了他们的__str__方法的对象,但是它行不通

我发现这是因为当我们使用 join 时,我们把它写成 ';'.join(l),所以 duck typing trick 对它不起作用,因为它使用 str 的方法而不是对象将被连接

但是为什么呢?既然许多内置的方法都设计为对鸭式输入友好,为什么不 'join'?

@SethMMorton 是我的疑惑,谢谢 我知道我可以使用 ';'.join([str(i) for i in l]) 来解决我的问题,但我不知道为什么 python 不自己做?

这不是鸭子打字的问题。您的自定义系列 class 中包含的项目存在问题。如果您尝试加入数字 range(),您将得到同样的错误。而是这样做:

';'.join(str(i) for i in l)

这在 string.join(iterable) 的文档中有清楚的解释:"Return a string which is the concatenation of the strings in the iterable iterable."

回答“为什么”:Python 中的所有内容都可以转换为 str,即使没有 __str__,对象的 repr 也会在 str 请求表格。 Python 可能很灵活,但是您所描述的是弱类型( Python 通常不会这样做),而不是鸭子类型。 __str__的存在意味着你可以强制到一个字符串,但它并不意味着“是一个字符串”。

允许使用 for 循环、zip 等迭代任意可迭代对象不是弱类型,因为它是一个没有歧义的通用接口;可迭代对象以相同的方式迭代,即使它们可能产生不同的类型。

实际的弱类型是危险的,因为它可以让错误悄无声息地传递。这在 Python 3 中尤为明显。如果允许自动强制转换为 str,而您这样做了:

iterable_of_bytes_objects = b'123', b'456'

','.join(iterable_of_bytes_objects)

你会默默地产生 "b'123',b'456'",当可能性很大时,你只是忘记了连接字符串上的前导 b,意思是:

b','.join(iterable_of_bytes_objects)

或者您可能打算生成一个字符串但忘记了 decode bytes。或者您可能想要每个对象的 repr,或 str,或其他任何内容。 Python 不知道,根据 Python 的禅 (import this):

In the face of ambiguity, refuse the temptation to guess.

以及:

Explicit is better than implicit.

强制自动隐藏错误并涉及对人们“可能想要”的东西的启发式猜测。如果你想强制,那就是 ','.join(map(str, iterable)) 的目的,但这意味着你选择了一种特定的强制形式,并且假设你知道自己在做什么,这符合其他 Zen 要求:

Errors should never pass silently.

Unless explicitly silenced.