为什么我不能将 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.
我正在研究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.