Как делает str.как startswith действительно работает?

Я немного играл с startswith() и я обнаружил кое-что интересное:

>>> tup = ('1', '2', '3')
>>> lis = ['1', '2', '3', '4']
>>> '1'.startswith(tup)
True
>>> '1'.startswith(lis)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: startswith first arg must be str or a tuple of str, not list

теперь ошибка очевидна, и приведение списка в кортеж будет работать так же хорошо, как и в первую очередь:

>>> '1'.startswith(tuple(lis))
True

Итак, мой вопрос: почему первым аргументом должен быть str или кортеж префиксов str, но не list ул. префиксы?

AFAIK, код Python для startswith() может выглядеть это:

def startswith(src, prefix):
    return src[:len(prefix)] == prefix

но это просто смущает меня больше, потому что даже с учетом этого все равно не должно иметь никакого значения, является ли список или кортеж. Что я упускаю ?

3 ответов


технически нет причин принимать другие типы последовательности, нет. The исходный код примерно это:

if isinstance(prefix, tuple):
    for substring in prefix:
        if not isinstance(substring, str):
            raise TypeError(...)
        return tailmatch(...)
elif not isinstance(prefix, str):
    raise TypeError(...)
return tailmatch(...)

(где tailmatch(...) выполняет фактическую работу сопоставления).

так что да, любой iterable сделал бы для этого for петли. Но все остальные API тестирования строк (а также isinstance() и issubclass()), которые принимают несколько значений, также принимают только кортежи, и это говорит вам как пользователю API, что безопасно предположить, что значение не мутировал. Вы не можете мутировать кортеж, но метод теоретически может мутировать список.

также обратите внимание, что вы обычно тест для фиксированного числа префиксов или суффиксов или классов (в случае isinstance() и issubclass()); реализация не подходит для большой количество элементов. Кортеж подразумевает, что у вас ограниченное количество элементов, а списки могут быть сколь угодно большими.

далее, если любой iterable или тип последовательности будет приемлемым, тогда это будет включать строки; одна строка -и последовательности. Тогда один строковый аргумент рассматриваться как отдельные символы, или как один префикс?

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

обратите внимание, что это было поднято ранее в списке идей Python; см. этой теме; главный аргумент Гвидо ван Россума заключается в том, что вы либо особый случай для отдельных строк, либо только для принятия кортежа. Он выбрал последнее и не видит необходимости менять это.


Это уже было предложено на Python-ideas пару лет назад см.:str.startswith принимая любые iterator, а не просто кортежа!--7--> и Гвр было сказал:

текущее поведение является преднамеренным, и двусмысленность строк сами итераторы-это главная причина. С startswith() is почти всегда вызывается с литералом или кортежем литералов в любом случае, я вижу маленькая потребность расширить семантика.

в дополнение к этому, казалось, не было никакой реальной мотивации, почему это сделать.

текущий подход держит вещи простыми и быстрыми, unicode_startswithendswith) проверьте аргумент кортежа, а затем для строки. Затем они называют tailmatch в нужном направлении. Это, возможно,очень легко понять в его текущем состоянии, даже для незнакомых с кодом C.

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


на аналогичной ноте, вот выдержка из выступления основного разработчика, Raymond Hettinger обсуждение вариантов дизайна API относительно определенных строковых методов, включая последние изменения str.startswith подпись. Хотя он кратко упоминает этот факт, что str.startswith принимает строку или кортеж строк и не излагает, разговор информативен о решениях и болевых точках, как основные разработчики, так и участники имели дело с до настоящего времени ПРИКЛАДНОЙ ПРОГРАММНЫЙ ИНТЕРФЕЙС.