为什么是string.join(list)而不是list.join(string)?

本文探讨了Python中使用`string.join(list)`而非`list.join(string)`的原因,涉及历史背景、性能和灵活性方面的考虑。Guido van Rossum在决定中指出,`join`作为字符串方法能更好地服务于各种可迭代对象,避免了额外的转换步骤和内存消耗。此外,文章还讨论了使用`string.join()`对于处理生成器表达式和不同数据类型的兼容性优势。
摘要由CSDN通过智能技术生成

这一直使我感到困惑。 看起来这样会更好:

my_list = ["Hello", "world"]
print(my_list.join("-"))
# Produce: "Hello-world"

比这个:

my_list = ["Hello", "world"]
print("-".join(my_list))
# Produce: "Hello-world"

是否有特定原因?


#1楼

这在String方法中进行了讨论...最终在Python-Dev中实现,并被Guido接受。 该线程始于1999年6月, str.join包含在2000年9月发布的Python 1.6中(并支持Unicode)。 Python 2.0(受支持的str方法包括join )于2000年10月发布。

  • 此线程中提出了四个选项:
    • str.join(seq)
    • seq.join(str)
    • seq.reduce(str)
    • 作为内置函数join
  • Guido希望不仅支持listtuple ,而且还支持所有序列/可迭代。
  • seq.reduce(str)对于新手来说很困难。
  • seq.join(str)引入了从序列到str / unicode的意外依赖关系。
  • join()作为内置函数将仅支持特定的数据类型。 因此,使用内置的名称空间是不好的。 如果join()支持许多数据类型,则创建优化的实现将很困难,如果使用__add__方法实现, __add__ O(n²)。
  • 分隔符( sep )不应省略。 显式胜于隐式。

此线程中没有其他原因。

以下是一些其他想法(我自己和我朋友的想法):

  • Unicode支持即将到来,但这不是最终的。 当时,UTF-8最有可能取代UCS2 / 4。 要计算UTF-8字符串的总缓冲区长度,需要知道字符编码规则。
  • 那时,Python已经决定了一个通用的序列接口规则,用户可以在其中创建类似序列的(可迭代)类。 但是Python直到2.2才支持扩展内置类型。 那时很难提供基本的可迭代类(在另一条评论中提到)。

Guido的决定记录在历史邮件中 ,决定使用str.join(seq)

有趣,但看起来确实正确! 巴里,去吧...
-吉多·范·罗苏姆(Guido van Rossum)


#2楼

为什么是string.join(list)而不是list.join(string)

这是因为join是一个“字符串”方法! 它从任何迭代创建一个字符串。 如果我们将方法卡在列表中,那么当我们拥有非列表的可迭代对象时该怎么办?

如果您有一个字符串元组怎么办? 如果这是一个list方法,则必须将每个这样的字符串迭代器都转换为list然后才能将元素连接到单个字符串中! 例如:

some_strings = ('foo', 'bar', 'baz')

让我们开始我们自己的列表连接方法:

class OurList(list): 
    def join(self, s):
        return s.join(self)

并且要使用它,请注意,我们必须首先从每个可迭代对象创建一个列表,以将该字符串连接到该可迭代对象,从而浪费内存和处理能力:

>>> l = OurList(some_strings) # step 1, create our list
>>> l.join(', ') # step 2, use our list join method!
'foo, bar, baz'

因此,我们看到我们必须添加一个额外的步骤来使用我们的列表方法,而不仅仅是使用内置的字符串方法:

>>> ' | '.join(some_strings) # a single step!
'foo | bar | baz'

发电机性能警告

Python使用str.join创建最终字符串的str.join实际上必须将可迭代对象传递两次,因此,如果为其提供生成器表达式,则必须先将其具体化为列表,然后才能创建最终字符串。

因此,尽管绕过生成器通常比列表理解更好, str.join是一个例外:

>>> import timeit
>>> min(timeit.repeat(lambda: ''.join(str(i) for i in range(10) if i)))
3.839168446022086
>>> min(timeit.repeat(lambda: ''.join([str(i) for i in range(10) if i])))
3.339879313018173

尽管如此, str.join操作在语义上仍然是“字符串”操作,因此将其放在str对象上而不是在其他可迭代对象上还是有意义的。


#3楼

-在“-”中。join(my_list)声明您正在从连接元素列表中转换为字符串。它以结果为导向。(为便于记忆和理解)

我制作了一个methods_of_string的详尽备忘单,供您参考。

string_methonds_44 = {
    'convert': ['join','split', 'rsplit','splitlines', 'partition', 'rpartition'],
    'edit': ['replace', 'lstrip', 'rstrip', 'strip'],
    'search': ['endswith', 'startswith', 'count', 'index', 'find','rindex', 'rfind',],
    'condition': ['isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isnumeric','isidentifier',
                  'islower','istitle', 'isupper','isprintable', 'isspace', ],
    'text': ['lower', 'upper', 'capitalize', 'title', 'swapcase',
             'center', 'ljust', 'rjust', 'zfill', 'expandtabs','casefold'],
    'encode': ['translate', 'maketrans', 'encode'],
    'format': ['format', 'format_map']}

#4楼

因为join()方法在字符串类中,而不是在列表类中?

我同意这看起来很有趣。

参见http://www.faqs.org/docs/diveintopython/odbchelper_join.html

历史记录。 当我第一次学习Python时,我期望join是一个列表方法,它将分隔符作为参数。 很多人都有同样的感觉,join方法背后还有一个故事。 在Python 1.6之前,字符串没有所有这些有用的方法。 有一个单独的字符串模块,其中包含所有字符串函数。 每个函数都将字符串作为其第一个参数。 这些功能被认为足够重要,足以放在字符串本身上,这对于诸如lower,upper和split这样的功能是有意义的。 但是许多铁杆Python程序员反对新的join方法,认为它应该是列表的方法,或者根本不应该移动,而只是保留旧字符串模块的一部分(仍然有很多字符串模块)里面有用的东西)。 我专门使用新的join方法,但是您会看到以任何一种方式编写的代码,如果确实困扰您,则可以使用旧的string.join函数。

--- Mark Pilgrim,深入Python


#5楼

这是因为任何iterable都可以联接,不仅是列表,而且结果和“ joiner”始终是字符串。

例如:

import urllib2
print('\n############\n'.join(
    urllib2.urlopen('http://data.stackexchange.com/users/7095')))

#6楼

主要是因为someString.join()的结果是一个字符串。

序列(列表或元组或其他)不会出现在结果中,只是一个字符串。 由于结果是字符串,因此作为字符串的方法是有意义的。


#7楼

我同意起初这是违反直觉的,但是有充分的理由。 Join不能成为列表的方法,因为:

  • 它也必须适用于不同的可迭代对象(元组,生成器等)
  • 在不同类型的字符串之间它必须具有不同的行为。

实际上有两种连接方法(Python 3.0):

>>> b"".join
<built-in method join of bytes object at 0x00A46800>
>>> "".join
<built-in method join of str object at 0x00A28D40>

如果join是列表的一种方法,则它必须检查其参数以确定要调用的参数。 而且您不能将byte和str结合在一起,因此它们现在的用法很有意义。


#8楼

将其视为拆分的自然正交运算。

我明白为什么它适用于任何可迭代的,所以不能轻易只是列表来实现。

为了提高可读性,我想用该语言查看它,但我认为这实际上是不可行的-如果可迭代性是一个接口,则可以将其添加到该接口中,但这只是一个约定,因此没有集中的方法将其添加到可迭代的事物集中。


#9楼

两者都不好。

string.join(xs,delimit)表示字符串模块知道列表的存在,这是没有业务可知的,因为字符串模块仅适用于字符串。

list.join(delimit)更好一点,因为我们习惯于将字符串作为基本类型(从语言上讲,它们是)。 但是,这意味着需要动态调度连接,因为在a.split("\\n")的任意上下文中,python编译器可能不知道a是什么,因此需要查找它(类似于vtable查找),这如果您多次这样做会很昂贵。

如果python运行时编译器知道列表是内置模块,则它可以跳过动态查找并将意图直接编码为字节码,否则,它需要动态地解析“ a”的“ join”,这可能是多层的每次调用的继承关系(因为两次调用之间,join的含义可能已更改,因为python是一种动态语言)。

可悲的是,这是抽象的最终缺陷。 无论您选择哪种抽象,您的抽象都仅在您要解决的问题的背景下才有意义,因此,当您开始将它们胶合在一起时,您将永远无法获得与基础意识形态相一致的一致抽象而不将它们包装在与您的意识形态相符的视图中。 知道了这一点,python的方法更灵活,因为它更便宜,您可以自己制作包装器或自己的预处理器,为此要花更多的钱才能使它看起来“更漂亮”。


#10楼

变量my_list"-"都是对象。 具体来说,它们分别是类liststr实例。 join函数属于str类。 因此,使用语法"-".join(my_list) ,因为对象"-"my_list作为输入。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值