Python join: почему это строка.присоединиться(список) вместо списка.присоединиться (строка)?



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



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


чем этот:



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


есть ли конкретная причина, что это так?

779   9  

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 как встроенная функция
  • Гвидо хотел поддержать не только list s,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

    Ничего не найдено.