with - sep join python




Python join: почему это string.join(list) вместо list.join(string)? (6)

Это меня всегда путало. Кажется, это было бы лучше:

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

Чем это:

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

Есть ли какая-то конкретная причина?


Почему это string.join(list) вместо list.join(string) ?

Это потому, что join - это «строковый» метод! Он создает строку из любого итерабельного. Если мы запустим метод в списках, то что, когда у нас есть итерации, которые не являются списками?

Что делать, если у вас есть кортеж строк? Если это был метод list , вам нужно было бы 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'

Поэтому мы видим, что нам нужно добавить дополнительный шаг для использования нашего метода списка, а не просто использовать встроенный метод string:

>>> ' | '.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 чем на разных итерациях.


Оба не хороши.

string.join (xs, delimit) означает, что строковый модуль знает о существовании списка, о котором он не знает о бизнесе, поскольку строковый модуль работает только со строками.

list.join (delimit) немного приятнее, потому что мы так привыкли к тому, что строки являются фундаментальным типом (и, на самом деле, они являются языком). Однако это означает, что соединение нужно отправлять динамически, потому что в произвольном контексте a.split("\n") компилятор python может не знать, что такое a, и ему нужно будет искать его (аналогично vtable lookup), который дорого, если вы делаете это много раз.

если компилятор времени выполнения python знает, что этот список является встроенным модулем, он может пропустить динамический поиск и напрямую закодировать намерение в байт-код, тогда как в противном случае ему необходимо динамически разрешить «соединение» «a», которое может быть на несколько уровней наследования на вызов (так как между вызовами смысл объединения может измениться, поскольку python является динамическим языком).

к сожалению, это конечная ошибка абстракции; независимо от того, какую абстракцию вы выберете, ваша абстракция будет иметь смысл только в контексте проблемы, которую вы пытаетесь решить, и поэтому вы никогда не сможете иметь последовательную абстракцию, которая не будет противоречить основополагающим идеологиям, когда вы начнете склеивать их вместе не обернув их взглядом, соответствующим вашей идеологии. Зная это, подход python более гибкий, поскольку он дешевле, вам нужно заплатить больше, чтобы он выглядел «лучше», либо создав собственную оболочку, либо ваш собственный препроцессор.


Поскольку метод join() находится в строчном классе, а не в классе списка?

Я согласен, что это выглядит забавно.

См. http://www.faqs.org/docs/diveintopython/odbchelper_join.html :

Историческая справка. Когда я впервые узнал Python, я ожидал, что join станет методом списка, который возьмет разделитель в качестве аргумента. Многие люди чувствуют то же самое, и есть история, стоящая за методом объединения. До Python 1.6 у строк не было всех этих полезных методов. Был отдельный строковый модуль, содержащий все строковые функции; каждая функция принимала строку в качестве первого аргумента. Функции считались достаточно важными, чтобы сами поместить на строки, что имело смысл для таких функций, как нижний, верхний и раскол. Но многие программисты на основе Python отказались от нового метода соединения, утверждая, что это должен быть метод списка вместо этого или что он не должен двигаться вообще, а просто оставаться частью старого строкового модуля (который все еще имеет множество полезных вещей в нем). Я использую только новый метод join, но вы увидите код, написанный в любом случае, и если это вас действительно беспокоит, вы можете использовать вместо него старую функцию string.join.

--- Марк Пилигрим, погрузитесь в Python


Прежде всего потому, что результат someString.join() - это строка.

Последовательность (список или кортеж или что-то еще) не появляется в результате, просто строка. Поскольку результатом является строка, это имеет смысл как метод строки.


Это связано с тем, что любой итеративный может быть объединен, а не только списки, но результат и «столяр» всегда являются строками.

НАПРИМЕР:

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

Я согласен с тем, что сначала это противоречит интуиции, но есть веская причина. Соединение не может быть методом списка, потому что:

  • он должен работать и для разных итераций (кортежи, генераторы и т. д.),
  • он должен иметь различное поведение между различными типами строк.

На самом деле существует два метода соединения (Python 3.0):

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

Если соединение было методом списка, тогда ему пришлось бы проверять его аргументы, чтобы решить, какой из них нужно вызвать. И вы не можете присоединиться к байту и str вместе, так что теперь у них есть смысл.





join