Это всегда смущало меня. Кажется, что это будет лучше
my_list = ["Hello", "world"]
print(my_list.join("-"))
# Produce: "Hello-world"
Чем это:
my_list = ["Hello", "world"]
print("-".join(my_list))
# Produce: "Hello-world"
Есть ли конкретная причина, по которой это так?
-
объявляет, что вы присоединяетесь к списку и конвертируете в строку. Она ориентирована на результат.str
чем реализовать ее для каждого итерируемого типа.Ответы:
Это потому, что любая итерация может быть объединена (например, list, tuple, dict, set), но результат и "joiner" должны быть строками.
Например:
Использование чего-то другого, кроме строк, вызовет следующую ошибку:
источник
list.join(string)
кажется более объектно-ориентированным подходом, тогда какstring.join(list)
звучит для меня гораздо более процедурно.print(str.join('-', my_list))
и это работает, чувствует себя лучше.__iter__
метод. Требование также реализовать все итерируемые объектыjoin
усложнит общий интерфейс (который также охватывает итерируемые элементы, не относящиеся к строкам) для очень конкретного случая использования. Определяемjoin
на побочных шагах эту проблему ценой «неинтуитивного» порядка. Лучшим выбором могло бы быть сохранение функции как функции с первым итеративным аргументом, а вторым (необязательным) как строкой соединения - но этот корабль уже прошел.Это обсуждалось в методах String ... наконец-то в Python-Dev achive, и было принято Гвидо. Эта тема началась в июне 1999 года и
str.join
была включена в Python 1.6, выпущенный в сентябре 2000 года (и поддерживающий Unicode). Python 2.0 (str
включая поддерживаемые методыjoin
) был выпущен в октябре 2000 года.str.join(seq)
seq.join(str)
seq.reduce(str)
join
как встроенная функцияlist
s,tuple
s, но и все последовательности / итерации.seq.reduce(str)
сложно для новичков.seq.join(str)
вводит неожиданную зависимость от последовательностей в str / unicode.join()
так как встроенная функция будет поддерживать только определенные типы данных. Таким образом, использование встроенного пространства имен не хорошо. Еслиjoin()
поддерживается много типов данных, создание оптимизированной реализации будет затруднено, если реализовано с использованием__add__
метода, то это O (n²).sep
) не должен быть опущен. Явное лучше, чем неявное.В этой теме нет других причин.
Вот некоторые дополнительные мысли (мои собственные и моего друга):
Решение Гвидо записывается в историческом письме , решая
str.join(seq)
:источник
Потому что
join()
метод находится в строковом классе, а не в списке класса?Я согласен, это выглядит смешно.
См. Http://www.faqs.org/docs/diveintopython/odbchelper_join.html :
источник
string
удалила все избыточныеstr
методы, поэтому вы больше не можете их использоватьstring.join()
. Лично я никогда не думал, что это «смешно», это имеет смысл, так как вы можете присоединиться к гораздо большему, чем просто списки, но присоединение - это всегда строка!Я согласен, что сначала это нелогично, но есть веская причина. Присоединение не может быть методом списка, потому что:
На самом деле есть два метода соединения (Python 3.0):
Если объединение является методом списка, то ему придется проверять свои аргументы, чтобы решить, какой из них вызывать. И вы не можете объединить байты и str вместе, поэтому то, что у них есть, теперь имеет смысл.
источник
Это потому, что
join
это «строковый» метод! Создает строку из любого итератора. Если мы поместим метод в списки, что делать, когда у нас есть итерации, которые не являются списками?Что делать, если у вас есть набор строк? Если бы это был
list
метод, вам пришлось бы приводить каждый такой итератор строк какlist
прежде, чем вы могли бы объединить элементы в одну строку! Например:Давайте свернем наш собственный метод соединения со списком:
И чтобы использовать его, обратите внимание, что мы должны сначала создать список из каждой итерации, чтобы объединить строки в эту итерацию, тратя впустую и память, и вычислительную мощность:
Итак, мы видим, что мы должны добавить дополнительный шаг, чтобы использовать наш метод списка, вместо того, чтобы просто использовать метод встроенной строки:
Предупреждение о производительности для генераторов
Алгоритм, который Python использует для создания окончательной строки,
str.join
фактически должен дважды передавать итеративное значение, поэтому, если вы предоставите ему выражение генератора, он должен сначала материализовать его в список, прежде чем сможет создать окончательную строку.Таким образом, хотя обход генераторов обычно лучше, чем списки,
str.join
исключение:Тем не менее, эта
str.join
операция все еще семантически является «строковой» операцией, поэтому все же имеет смысл иметь ее наstr
объекте, а не на других итерациях.источник
Думайте об этом как о естественной ортогональной операции разделения.
Я понимаю, почему это применимо к чему-либо повторяемому и поэтому не может быть легко реализовано только в списке.
Для удобства чтения я хотел бы видеть это на языке, но я не думаю, что это на самом деле выполнимо - если бы итеративность была интерфейсом, то его можно было бы добавить к интерфейсу, но это просто соглашение, и поэтому нет никакого центрального способа добавьте его в набор вещей, которые можно повторять.
источник
Прежде всего потому, что результатом
someString.join()
является строка.Последовательность (список, кортеж или что-то еще) не появляется в результате, просто строка. Поскольку результатом является строка, это имеет смысл как метод строки.
источник
-
в "-". join (my_list) объявляет, что вы конвертируете в строку из соединяемых элементов список. Он ориентирован на результат (просто для удобства памяти и понимания)Я делаю исчерпывающую таблицу для Methods_of_string для вашей справки.
источник
Оба не хороши.
string.join (xs, delimit) означает, что строковый модуль знает о существовании списка, о котором он не знает, поскольку строковый модуль работает только со строками.
list.join (delimit) немного лучше, потому что мы так привыкли к тому, что строки являются фундаментальным типом (и, говоря языком, они есть). Однако это означает, что join должен отправляться динамически, потому что в произвольном контексте
a.split("\n")
компилятор python может не знать, что такое a, и должен будет искать его (аналогично vtable lookup), что дорого, если вы делаете это много раз.если компилятор времени выполнения Python знает, что список является встроенным модулем, он может пропустить динамический поиск и напрямую зашифровать намерение в байт-код, тогда как в противном случае ему необходимо динамически разрешить «соединение» из «а», которое может занимать несколько уровней наследования за вызов (поскольку между вызовами значение соединения могло измениться, потому что python является динамическим языком).
к сожалению, это абсолютный недостаток абстракции; Независимо от того, какую абстракцию вы выберете, ваша абстракция будет иметь смысл только в контексте проблемы, которую вы пытаетесь решить, и поэтому вы никогда не сможете получить последовательную абстракцию, которая не станет несовместимой с основными идеологиями, когда вы начнете склеивать их. вместе, не оборачивая их в соответствии с вашей идеологией. Зная это, подход python более гибок, поскольку он дешевле, и вам нужно платить больше, чтобы он выглядел «лучше», либо создавая свою собственную обертку, либо свой собственный препроцессор.
источник
Переменные
my_list
и"-"
являются объектами. В частности, они являются экземплярами классовlist
иstr
, соответственно.join
Функция принадлежит к классуstr
. Таким образом, синтаксис"-".join(my_list)
используется, потому что объект"-"
принимаетmy_list
в качестве входных данных.источник