这个问题一直让我困扰。似乎这样会更好:
["Hello", "world"].join("-")
比这个:
"-".join(["Hello", "world"])
这样做的特定原因是什么?
这是因为任何可迭代对象都可以连接起来(例如列表、元组、字典、集合),但其内容和“连接器”必须是字符串。
例如:
'_'.join(['welcome', 'to', 'stack', 'overflow'])
'_'.join(('welcome', 'to', 'stack', 'overflow'))
'welcome_to_stack_overflow'
使用非字符串类型将引发以下错误:
TypeError: sequence item 0: expected str instance, int found
list.join(string)
看起来更像一种面向对象的方法,而 string.join(list)
对我来说听起来更加过程化。 - Eduardo Pignatelliprint(str.join('-', my_list))
,它能正常工作,感觉更好。 - pimgeek__iter__
方法的类型都可以是可迭代对象。要求所有可迭代对象都实现 join
方法将会使得通用接口变得更加复杂(该接口还覆盖了非字符串类型的可迭代对象),只是为了解决一个非常特定的问题。在字符串上定义 join
方法避免了这个问题,但代价是顺序“不直观”。可能更好的选择是保持 join
作为一个函数,第一个参数是可迭代对象,第二个参数(可选)是连接符字符串——但这已经成为了既定事实。 - user4815162342str.join
被包含在于2000年9月发布的Python 1.6中(并支持Unicode)。Python 2.0(支持str
方法,包括join
)于2000年10月发布。separator.join(items)
items.join(separator)
items.reduce(separator)
join
作为内置函数list
和tuple
,还支持所有的序列/可迭代对象。items.reduce(separator)
很难理解。
items.join(separator)
将序列与字符串/Unicode之间引入了意外的依赖关系。
join()
作为一个独立的内置函数只能支持特定的数据类型。因此,使用内置命名空间并不好。如果join()
要支持多种数据类型,创建一个优化的实现将会很困难:如果使用__add__
方法来实现,时间复杂度将是O(n²)。separator
)不应该被省略。明确比隐式更好。Guido的决定记录在一封历史邮件中,决定使用separator.join(items)
:
有趣,但似乎是正确的!Barry,去做吧...
--Guido van Rossum
string.join(sep, seq)
或类似的方法。 ♂️ - Jason Cstr.join(",", ["a", "b", "c"])
返回 "a,b,c"
。 - undefinedjoin()
方法存在于字符串类中,而不是列表类中。
参见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,《Dive into Python》string
库已经移除了所有冗余的str
方法,所以您无法再使用string.join()
。就个人而言,我从未觉得它有多“有趣”,它非常合理,因为您可以连接不止列表,但连接器始终是一个字符串! - Martijn Pietersstr.join(str_instance, list[str])
代替 string.join(str_instance, list[str])
。这样做的好处是,您不需要为这种基本功能导入任何模块。 - Tigran我同意这一点起初可能不太直观,但有一个很好的原因。Join不能是列表的方法,因为:
实际上有两种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是列表的一个方法,那么它必须检查它的参数以决定调用哪个参数。而且你不能将字节和字符串连接在一起,所以现在他们这样做是有意义的。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
是一个例外:
>>> 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
对象上拥有它比在其他迭代对象上拥有它更有意义。
把它看作是“split”操作的自然正交操作。
我理解为什么它适用于任何可迭代对象,因此不能仅仅在列表上实现。
为了可读性,我希望在语言中看到它,但我不认为这是实际可行的-如果可迭代性是一个接口,那么它可以添加到接口中,但它只是一种约定,因此没有集中的方法将其添加到可迭代的事物集合中。
-
在 "-".join(my_list)
中表示将列表中的元素连接起来并转换为字符串。这是结果导向的。(只为了更容易记住和理解)
我制作了一份详尽的字符串方法速查表供您参考。
string_methods_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']}
主要是因为 someString.join()
的结果是一个字符串。
序列(列表、元组或其他类型)不会出现在结果中,只有一个字符串。由于结果是一个字符串,因此作为字符串的方法是有意义的。
您不仅可以连接列表和元组。您几乎可以连接任何可迭代对象。可迭代对象包括生成器、映射、过滤器等。
>>> '-'.join(chr(x) for x in range(48, 55))
'0-1-2-3-4-5-6'
>>> '-'.join(map(str, (1, 10, 100)))
'1-10-100'
使用生成器、映射、过滤等功能的美妙之处在于它们占用的内存很少,几乎可以即刻创建。
这正是为什么它们在概念上如此重要的另一个原因。
str.join(<iterator>)
只有授予str这种能力才是高效的。而不是授予所有迭代器(列表、元组、集合、字典、生成器、映射、过滤器)都具有对象作为共同父级的join。
当然,range()和zip()也是迭代器,但它们永远不会返回str,因此不能与str.join()一起使用。
>>> '-'.join(range(48, 55))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: sequence item 0: expected str instance, int found
iter.join()
)。” - zdimmy_list
和"-"
都是对象。具体来说,它们分别是类list
和str
的实例。函数join
属于类str
。因此,使用语法"-".join(my_list)
是因为对象"-"
将my_list
作为输入。
-
表示将列表连接并转换为字符串。它关注的是结果。 - AbstProcDostr.split()
返回一个非字符串类型,这很有道理。在这里似乎使用相同的逻辑也应该没问题,对吗?(仅探讨非字符串输出的概念性问题) - ntjess