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

时间:2009-01-29 22:45:14

标签: python string list join

这一直困扰着我。看起来这会更好:

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

比这个:

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

是否有这样的具体原因?

10 个答案:

答案 0 :(得分:1161)

这是因为任何iterable都可以连接,而不仅仅是列表,但结果和“joiner”总是字符串。

E.G:

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

答案 1 :(得分:259)

这在Python-Dev achive的String methods... finally主题中进行了讨论,并被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不仅支持list s,tuple s,还支持所有序列/可迭代。
  • seq.reduce(str)对于新来者来说很难。
  • seq.join(str)引入了从序列到str / unicode的意外依赖。
  • join()作为内置函数仅支持特定数据类型。因此使用内置命名空间并不好。如果join()支持许多数据类型,那么创建优化的实现将很困难,如果使用__add__方法实现,则它是O(n²)。
  • 不应省略分隔符字符串(sep)。显式优于隐式。

此线程中没有其他原因。

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

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

Guido的决定记录在historical mail,决定str.join(seq)

  

有趣,但看起来确实合适!巴里,去吧......   --Guido van Rossum

答案 2 :(得分:243)

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

我同意这看起来很有趣。

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

  

历史记录。当我第一次学习时   Python,我希望join成为一种方法   列表,这将采取   分隔符作为参数。很多   人们也有同感,并且有   连接方法背后的故事。先   到Python 1.6,字符串并不是全部   这些有用的方法。有一个   单独的字符串模块包含   所有的字符串函数;每   函数首先使用字符串   论点。功能被认为是   足够重要的东西   字符串本身,这是有道理的   用于下,上,和等功能   分裂。但是很多硬核Python   程序员反对新的加入   方法,认为它应该是一个   相反的方法,或它的方法   根本不应该移动,而只是停留   旧字符串模块的一部分(其中   还有很多有用的东西)。   我只使用新的连接方法,   但你会看到编写的代码   方式,如果它真的困扰你,你   可以使用旧的string.join函数   代替。

     

--- Mark Pilgrim,潜入Python

答案 3 :(得分:62)

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

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

实际上有两种连接方法(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连接在一起,所以他们现在拥有它的方式是有道理的。

答案 4 :(得分:41)

  

为什么string.join(list)代替list.join(string)

这是因为join是&#34;字符串&#34;方法!它从任何可迭代创建一个字符串。如果我们把这个方法放在列表上,那么当我们有不列出的迭代列表时呢?

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

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

让我们推出自己的列表连接方法:

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

要使用它,请注意我们必须首先从每个iterable中创建一个列表以加入该iterable中的字符串,从而浪费内存和处理能力:

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

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

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

发电机性能警告

Python用于创建带有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操作在语义上仍然是一个&#34;字符串&#34;操作,所以它在str对象上比在其他迭代上更有意义。

答案 5 :(得分:23)

将其视为拆分的自然正交操作。

我理解为什么它适用于任何可迭代的内容,因此无法在列表中轻松实现

为了便于阅读,我希望在语言中看到它,但我不认为这实际上是可行的 - 如果迭代是一个接口,那么它可以添加到接口但它只是一个约定,所以没有将它添加到可迭代的事物的集中方式。

答案 6 :(得分:12)

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

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

答案 7 :(得分:6)

- in&#34; - &#34; .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']}

答案 8 :(得分:2)

两者都不好。

string.join(xs,delimit)意味着字符串模块知道列表的存在,它没有业务知道,因为字符串模块只适用于字符串。

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

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

遗憾的是,这是抽象的最终缺陷;无论你选择什么抽象,你的抽象只会在你试图解决的问题的上下文中有意义,因此当你开始粘合它们时,你永远不会有一个与底层意识形态不一致的一致抽象在没有将它们包裹在与您的意识形态一致的视图中的情况下。知道了这一点,python的方法更灵活,因为它更便宜,你需要付出更多才能让它看起来“更好”,无论是制作你自己的包装器,还是你自己的预处理器。

答案 9 :(得分:0)

变量Energy_y 1 2 3 4 5 6 7 8 9 10 Energy_x 1 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 1 0 0 3 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 1 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0 9 0 0 1 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 0 0 0 my_list都是对象。具体来说,它们分别是类"-"list的实例。 str函数属于类join。因此,使用语法str是因为对象"-".join(my_list)"-"作为输入。