Python join: почему это строка.присоединиться(список) вместо списка.присоединиться (строка)?
это всегда смущало меня. Кажется, это было бы лучше:
my_list = ["Hello", "world"]
print my_list.join("-")
# Produce: "Hello-world"
чем этот:
my_list = ["Hello", "world"]
print "-".join(my_list)
# Produce: "Hello-world"
есть ли конкретная причина, что это так?
9 ответов:
это потому, что любой iterable может быть объединен, а не только списки, но результат и "столяр" всегда являются строками.
Например:
import urllib2 print '\n############\n'.join( urllib2.urlopen('http://data.stackexchange.com/users/7095'))
, потому что
join()метод в класс String, вместо класса список?Я согласен, что это выглядит смешно.
см.http://www.faqs.org/docs/diveintopython/odbchelper_join.html:
историческая справка. когда я впервые узнал Python, я ожидал, что join будет методом из списка, который бы взял разделитель в качестве аргумента. Очень много люди чувствуют то же самое, и там история, лежащая в основе метода join. Прежде для Python 1.6 строки не имели всех это полезные методы. Там был отдельный строковый модуль, который содержал все строковые функции; каждая функция взяла строку в качестве первой аргумент. Функции были сочтены достаточно важно, чтобы положить на сами струны, что имело смысл для таких функций, как нижний, верхний и расщеплять. Но многие жесткие ядра Python программисты возражали против нового объединения метод, утверждая, что это должно быть метод списка или что оно не должен двигаться вообще, а просто остаться часть старого строкового модуля (который еще есть много полезных вещей в нем). Я использую новый метод соединения исключительно, но вы увидите код, написанный либо кстати, и если это тебя действительно беспокоит, то ты можно использовать старую строку.функция соединения вместо.
--- Марк Пилигрим, погружение в Python
это обсуждалось в 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как встроенная функция- Гвидо хотел поддержать не только
lists,tuples, но все последовательности / iterables.seq.reduce(str)трудно для новичков.seq.join(str)вводит неожиданную зависимость от последовательностей в str / unicode.join()как встроенная функция будет поддерживать только определенные данные типы. Поэтому использование встроенного пространства имен не очень хорошо. Еслиjoin()поддерживает множество типов данных, создание оптимизированной реализации будет затруднено, если реализовано с помощью__add__метод, то это O (n2).- строковый разделитель (
sep) не следует опускать. Явное лучше, чем неявное.в этой теме нет других причин.
вот некоторые дополнительные мысли (мои собственные, и моего друга):
- поддержка Unicode шла, но она не была окончательной. В то время UTF-8, скорее всего, собирался заменить UCS2/4. Для вычисления общей длины буфера строк UTF-8 необходимо знать правило кодирования символов.
- в то время Python уже определился с общим правилом интерфейса последовательности, в котором пользователь может создать последовательный (итерационный) класс. Но Python не поддерживал расширение встроенных типов до 2.2. В то время это было трудно предоставьте базовый итерационный класс (который упоминается в другом комментарии).
решение Гвидо записывается в исторические почта, определения
str.join(seq):смешно, но это кажется правильным! Барри, давай...
-- Гвидо ван Россум
Я согласен, что это нелогично сначала, но есть веская причина. 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 вместе, поэтому то, как они это сейчас делают, имеет смысл.
почему
string.join(list)вместоlist.join(string)?это так
joinэто метод "string"! Он создает строку из любого iterable. Если мы застряли метод в списках, как насчет того, когда у нас есть iterables, которые не являются списками?что делать, если у вас есть набор строк? Если бы это было
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объект, чем на разных итерациях.
думайте об этом как о естественной ортогональной операции для разделения.
Я понимаю, почему он применим к чему-либо итерируемому и поэтому не может быть легко реализован просто на список.
для удобства чтения я хотел бы видеть его на языке, но я не думаю, что это действительно возможно - если бы итеративность была интерфейсом, то ее можно было бы добавить к интерфейсу, но это просто соглашение, и поэтому нет центрального способа добавить его к набору вещей, которые являются повторяемый.
в первую очередь потому, что результат a
someString.join()- это строка.последовательность (список или кортеж или что-то еще) не появляется в результате, просто строка. Поскольку результатом является строка, это имеет смысл как метод строки.
-в "-".join (my_list) объявляет, что выполняется преобразование в строку из соединяемых элементов a list.It ориентирован на результат.(только для легкой памяти и понимания)Я делаю исчерпывающий cheatsheet 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']}
оба не очень хорошо.
строку.join (xs, delimit) означает, что строковый модуль знает о существовании списка, о котором он не знает, поскольку строковый модуль работает только со строками.
список.join (delimit) немного лучше, потому что мы так привыкли к тому, что строки являются фундаментальным типом(и, говоря языком, они есть). Однако это означает, что join должен быть отправлен динамически, потому что в произвольном контексте
a.split("\n")компилятор python возможно, вы не знаете, что такое a, и вам нужно будет искать его(аналогично поиску vtable), что дорого, если вы делаете это много раз.если в Python во время выполнения компилятор знает, что список представляет собой встроенный модуль, он может пропустить динамический поиск и кодирования намерениях в байт-код напрямую, тогда как в противном случае он должен оперативно решать "присоединиться" на "А", который может быть до нескольких слоев наследованию на вызов(т. к. между вызовами, смысл присоединиться может измениться, потому что Python-это динамический язык.)
Comments