Почему python запрещает использование суммы со строками? [Дубликат]

Использовать try catch с бесконечным циклом while. Чтобы проверить пустую строку, используйте инструкцию IF, чтобы проверить, является ли строка пустой.

while True:
    name = input("Enter Your Name\n")
    if not name:
        print("I did not understood that")
        continue
    else:
        break

while True:
    try:
        salary = float(input("whats ur salary\n"))
    except ValueError:
        print("I did not understood that")
        continue
    else:
        break

while True:
    try:
        print("whats ur age?")
        age = int(float(input()))
    except ValueError:
        print("I did not understood that")
        continue
    else:
        break

print("Hello "+ name +  "\nYour salary is " + str(salary) + '\nand you will be ' + str(age+1) +' in a Year')
60
задан Dima Tisnek 28 April 2014 в 17:47
поделиться

8 ответов

Python пытается отговорить вас от «суммирования» строк. Вы должны присоединиться к ним:

"".join(list_of_strings)

Это намного быстрее и использует гораздо меньше памяти.

Быстрый тест:

$ python -m timeit -s 'import operator; strings = ["a"]*10000' 'r = reduce(operator.add, strings)'
100 loops, best of 3: 8.46 msec per loop
$ python -m timeit -s 'import operator; strings = ["a"]*10000' 'r = "".join(strings)'
1000 loops, best of 3: 296 usec per loop

Edit (чтобы ответить на редактирование OP): Что касается того, почему строки были, по-видимому, «выделены», я считаю, что это просто вопрос оптимизации для общего случая, а также для обеспечения наилучшей практики: вы можете присоединяться к строкам намного быстрее с помощью ''. join, поэтому явно запрещающие строки на sum укажут это на новичков.

Кстати, это ограничение было на месте «навсегда», т. е. поскольку sum был добавлен как встроенный функция [ rev. 32347 )

47
ответ дан rbp 21 August 2018 в 07:27
поделиться
  • 1
    На самом деле, я думаю, что все наоборот: reduce и sum похожи для списков, потому что они делают более или менее одно и то же. Вот почему я использовал этот тест: reduce, представляющий sum, по сравнению с join, который является оптимизированным способом «добавления». строки. – rbp 19 August 2010 в 20:54
  • 2
    Теперь я чувствую себя старым. Я понимаю «навсегда». в Python, как и раньше 2.0. Вещи, сделанные после введения новых классов стиля, не так «навсегда». – Muhammad Alkarouri 19 August 2010 в 20:55
  • 3
    Похоже, что это «непитонический». чтобы препятствовать этому использованию. Я согласен с Мухаммадом в том, что это странное исключение. Но, похоже, это лучшая причина. – Edmund 20 August 2010 в 06:53
  • 4
    Я думаю, что это происходит из-за хронологической последовательности реализаций: когда они реализовали встроенный sum, они уже имели join для строк. Поэтому, чтобы избегать людей неосознанно (или сознательно, но лениво / озорно), используя sum для строк, они специально запретили его. Поскольку не было конкретной «суммы», для списков (или других типов) они делали исключение только для строк. В настоящее время я думаю, что они сохранили бы его таким образом, даже если бы кто-то придумал конкретную «сумму» для обратной совместимости. – rbp 23 August 2010 в 01:46
  • 5
    Это не оптимизирует общий случай. Оптимизация будет использовать тот же самый оператор if, блокирующий его, чтобы вместо этого вызывать код (уже написанный) str.join. Поскольку это была бы такая легкая оптимизация, я бы предположил, что намерение состоит в том, чтобы умышленно обманывать, чтобы научить людей существованию str.join. – Ben 30 April 2014 в 22:41

Краткий ответ: Эффективность.

Длинный ответ: функция sum должна создать объект для каждой частичной суммы.

Предположим, что время, необходимое для создания объект прямо пропорционален размеру его данных. Пусть N обозначает количество элементов в последовательности для суммирования.

double s всегда одного размера, что делает время работы sum O (1) × N = O (N) .

int (ранее известное как long) является произвольной длиной. Обозначим через M абсолютное значение наибольшего элемента последовательности. Тогда наихудшее время работы sum: lg (M) + lg (2M) + lg (3M) + ... + lg (NM) = N × lg (M) + lg (N!) = O (N log N).

Для str (где M = длина самой длинной строки) наихудшее время работы: M + 2M + 3M + ... + NM = M × (1 + 2 + ... + N) = O (N²).

Таким образом, строки sum ming будут намного медленнее, чем sum числа ming.

str.join не выделяет никаких промежуточных объектов. Он предопределяет буфер, достаточно большой для хранения объединенных строк, и копирует строковые данные. Он работает в O (N) раз, намного быстрее, чем sum.

10
ответ дан dan04 21 August 2018 в 07:27
поделиться
  • 1
    Этот аргумент неверен, потому что то же самое можно было бы использовать для списков и кортежей, которые можно суммировать. Как указано HS, Python явно проверяет строки и только для строк, что просто не имеет смысла. – Philipp 20 August 2010 в 07:08
  • 2
    @Philipp: недостающая часть состоит в том, что многие, многие люди пытались использовать sum для строк, и не многие используют sum для списков и кортежей. Ловушка заключается в том, что sum отлично работает для коротких списков строк, но затем запускается в производство, где списки могут быть огромными, а производительность замедляется до обхода. Это была такая общая ловушка, что было принято решение игнорировать утиную печать в этом случае и не допускать использования строк с sum. – Ethan Furman 28 April 2014 в 21:01
  • 3
    Отличный ответ. За исключением "будет намного медленнее" должен быть «намного медленнее», как было доказано. – steffen 25 November 2016 в 07:19

Изменить: перемещение частей относительно неизменяемости в историю.

В принципе, это вопрос предварительного распределения. Когда вы используете инструкцию типа

sum(["a", "b", "c", ..., ])

и ожидаете, что она будет работать аналогично оператору reduce, генерируемый код выглядит примерно как

v1 = "" + "a" # must allocate v1 and set its size to len("") + len("a")
v2 = v1 + "b" # must allocate v2 and set its size to len("a") + len("b")
...
res = v10000 + "$" # must allocate res and set its size to len(v9999) + len("$")

. В каждом из этих шаги создают новую строку, которая может дать некоторые накладные расходы на копирование, поскольку строки становятся длиннее и длиннее. Но, может быть, и не здесь. Более важно то, что каждая новая строка в каждой строке должна быть выделена для определенного размера (что. Я не знаю, что она должна выделяться на каждой итерации оператора reduce, там может быть некоторые очевидные эвристики для использования, и Python может выделить немного больше здесь и там для повторного использования, но в нескольких точках новая строка будет достаточно большой, чтобы это больше не помогло, и Python должен снова выделить, что довольно дорого.

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

3
ответ дан Debilski 21 August 2018 в 07:27
поделиться
  • 1
    Это правда, но это не вся история. Целые числа также неизменяемы. Но операция соединения по строкам является специализированной, учитывает весь список и, следовательно, намного быстрее. – rbp 19 August 2010 в 20:30
  • 2
    Да, хорошо, может быть, неизменность здесь не проблема. (Хотя я могу себе представить, что целые числа в регистре страдают меньше от неизменяемости на стороне Python, чем строки). Но тогда я думаю, что preallocation фактически является всей историей. – Debilski 19 August 2010 в 20:37
  • 3
    @Debiliski: Предпосылка была, вероятно, недостающим звеном для меня; он говорит, почему "",join ведет себя намного лучше, чем общая сумма. Мне пришлось посмотреть код , чтобы понять. Я думаю, что неизменность - это красная селедка. – Muhammad Alkarouri 19 August 2010 в 21:22
  • 4
    @Debiliski: К сожалению, я принял другой ответ, иначе я бы предположил, что вы отредактируете свое, чтобы сделать предварительное распределение и объяснение более заметными. – Muhammad Alkarouri 19 August 2010 в 21:23
  • 5
    Предоставляет ли он на самом деле предварительное распределение? Аргумент Join может быть произвольным итератором, который вы могли бы выполнить только один раз. Не зная кода, я бы предположил, что ключевой момент - на уровне C у вас есть перенасеченный массив, который вы можете мутировать на месте; поскольку он не был выпущен в код python, но это не нарушает «строки python, которые являются неизменяемыми». закон. Повторное распределение / копирование может быть амортизировано до O (n), если вы всегда увеличиваете размер по крайней мере вдвое, если вам нужно больше (вместо того, чтобы делать это для каждой строки). – Ben 30 April 2014 в 22:53

Я не знаю почему, но это работает!

import operator
def sum_of_strings(list_of_strings):
    return reduce(operator.add, list_of_strings)
2
ответ дан Dinesh Panchananam 21 August 2018 в 07:27
поделиться
  • 1
    Поскольку reduce не sum, но он будет по-прежнему иметь ужасную производительность для больших списков. – Ethan Furman 22 November 2014 в 02:36

Причина, по которой

@ dan04 имеет прекрасное объяснение затрат на использование sum в больших списках строк.

Недостающий вопрос о том, почему str не разрешено для sum, состоит в том, что многие, многие люди пытались использовать sum для строк, и не многие используют sum для списков и кортежей и других структур данных O (n ** 2). Ловушка заключается в том, что sum отлично работает для коротких списков строк, но затем запускается в производство, где списки могут быть огромными, а производительность замедляется до обхода. Это была такая общая ловушка, что было принято решение игнорировать утиную печать в этом случае и не допускать использования строк с sum.

9
ответ дан Ethan Furman 21 August 2018 в 07:27
поделиться
  • 1
    Есть ли какая-либо причина, по которой реализация sum() не просто вызывает ''.join(), когда строка встречается в sum() вместо того, чтобы возвращать ошибку, указав, что вы вызываете ''.join()? – Slater 28 April 2014 в 21:13
  • 2
    @Slater: Да. Но я не помню, что это было. :( – Ethan Furman 28 April 2014 в 23:06

Вот источник: http://svn.python.org/view/python/trunk/Python/bltinmodule.c?revision=81029&view=markup

в функции builtin_sum мы имеем этот бит кода:..

     /* reject string values for 'start' parameter */
        if (PyObject_TypeCheck(result, &PyBaseString_Type)) {
            PyErr_SetString(PyExc_TypeError,
                "sum() can't sum strings [use ''.join(seq) instead]");
            Py_DECREF(iter);
            return NULL;
        }
        Py_INCREF(result);
    }

Так .. что ваш ответ

Это явно проверяется в коде и отвергнуто

14
ответ дан HS. 21 August 2018 в 07:27
поделиться
  • 1
    Интересно видеть код, но вопрос был « Why не содержит строки, а не« How ), они исключали строки из суммирования? & Quot; ... – Edmund 20 August 2010 в 06:47
  • 2
    Ну, я имел в виду, причина, почему его не работает, потому что он явно запрещен в коде. Другие, казалось, отвечали, объясняя, почему вы не должны этого делать. – HS. 20 August 2010 в 08:35
  • 3
  • 4

Фактически вы можете использовать sum(..) для конкатенации строк, если вы используете соответствующий начальный объект! Конечно, если вы заходите так далеко, вы уже достаточно поняли, чтобы использовать "".join(..) в любом случае ..

>>> class ZeroObject(object):
...  def __add__(self, other):
...   return other
...
>>> sum(["hi", "there"], ZeroObject())
'hithere'
24
ответ дан u0b34a0f6ae 21 August 2018 в 07:27
поделиться
  • 1
    Я нахожу это очень интересным. Конечно, это слишком умно, наполовину, но это добавляет понимание этой функции. – Muhammad Alkarouri 19 August 2010 в 21:39
  • 2
    И это немного быстрее, чем сокращенная версия. – Debilski 19 August 2010 в 23:06
  • 3
    Тем не менее это странно, что Python проверяет строки, но не для списков или кортежей. – Philipp 20 August 2010 в 07:14

Из docs :

Предпочтительным, быстрым способом объединения последовательности строк является вызов '.join (sequence).

Делая sum отказаться от работы с строками, Python рекомендует вам использовать правильный метод.

13
ответ дан unutbu 21 August 2018 в 07:27
поделиться
  • 1
    Так что это часть философии «одного из способов сделать это». (Так как они могли бы просто сделать суммы лечить строки специально) – Thomas Ahle 13 February 2014 в 15:43
  • 2
    @ThomasAhle: Существует вычислительная причина, по которой sum является неправильным инструментом для работы. sum строит результат пошагово. Для этого со строками требуется (потенциально много) временных неизменяемых строк. Если это делается наивно, для этого процесса требуется много временной памяти и много копий. Напротив, если сделать это с ''.join(), соответствующий объем памяти выделяется с самого начала, и результат строится прямо там сразу. См. увещевание Мартелли . – unutbu 13 February 2014 в 15:56
  • 3
    Конечно, но вы можете делать много неэффективных вещей на Python, и часто это не имеет значения. Я не могу думать ни о каких других случаях, кроме «суммы строк», где есть тесты против чего-то, жестко закодированные в коде Python C! – Thomas Ahle 13 February 2014 в 16:39
Другие вопросы по тегам:

Похожие вопросы: