Почему существует "int + string" в статически типизированном С#, но не в динамически типизированном Python?

Во время изучения С# мне показалось странным, что динамически типизированный Python поднимет ошибку в следующем коде:

i = 5
print i + " "

тогда как статически типизированный С#, как правило, будет работать с аналогичным кодом:

int i = 5;
Console.Write(i + " ");

Я бы ожидал другого пути (в python я смог бы сделать это без кастингов, но С# потребовал бы, чтобы я использовал int для string или string для int).

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

Ответ 1

Это не статический/динамический вопрос, а вопрос философии языка.

В Python + определяется как добавление для чисел и конкатенация для строк. Это вполне разумное поведение, если у вас даже небольшой опыт программирования.

Но когда у вас есть один, каждый, что происходит? Он пытается преобразовать строку в число или преобразовать число в строку? Любой из них также является совершенно разумным поведением для любого, кто вообще программировал, но поскольку разные языки имеют разные правила о том, как это происходит, вы можете сделать предположения отличными от тех, которые кто-то еще сделает в зависимости от того, какие языки у вас есть с уже.

Python как один из своих руководящих принципов "явный лучше, чем неявный" (import this), и поэтому он позволяет вам четко указать, какое поведение вы хотите. Как? Конечно, преобразование строки или числа в нужный тип. Тогда они оба являются строками или обоими числами, и поведение очевидно.

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

Ответ 2

Вы правы, что здесь что-то странно. Что странно, так это то, что + означает конкатенацию строк на любом языке! Независимо от того, может ли + объединить int в строку или нет, это небольшая точка по сравнению с странностью, которая + означает "concatenate" вообще.

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

  • Дополнение является коммутативным, но конкатенация строк - нет. x + y!= y + x
  • Дополнение является ассоциативным, но конкатенация строк в С# не является. (x + y) + z не обязательно равна x + (y + z), если, например, y и z являются целыми числами.
  • Дополнение сопряжено с обратной операцией, вычитанием, с тем свойством, что если x + y равно z, то z - y - x. Для строк нет такой операции.
  • Дополнение имеет левое и правое тождество, а также конкатенация строк. (Пустая строка).

Один из четырех не очень хорош. Конкатенация строк очень не похожа на добавление, поэтому зачем им делиться оператором?

Я не говорю это часто, но C получил это право. Оператор конкатенации строк должен быть таким: конкатенация. В C "X" "Y" означает "XY". Если вы ставите две строковые литералы рядом друг с другом, они объединяются в третью.

Ответ 3

Это не область статической и динамической типизации. Скорее его сильная и слабая типизация (по крайней мере, по какой-то часто используемой терминологии, которую Википедия также использует в своей характеристике языков программирования). И С# и Python строго типизированы (по этому определению).

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

Так получилось, что в вашей конкретной ситуации С# перегружает operator + для строк и чисел (фактически, произвольных объектов), где Python doesnt. Это, вероятно, делает Python немного более строгим в этом случае.

Ответ 4

Для С# существует метод ToString() для Int32 (int) и почти всех типов в этом отношении - типы указателей являются исключением в этом случае.

Класс String в С# перегрузил оператор +, который в этом случае просто вызывает вызов String.Concat(Object, Object).

По-моему, это скорее результат работы .NET Framework, чем что-либо еще.

Ответ 5

Динамическое типирование на самом деле не вступает в игру здесь, оба языка понимают, что я - это int, а "" - строка. Разница в том, что С# имеет функцию +, которая принимает (int, string) аргументы, Python этого не делает.

Ответ 6

Понимание модели данных python (http://docs.python.org/2/reference/datamodel.html#emulating-numeric-types) поможет вам здесь.

Когда вы выполняете a + b, это переводится в a.__add__(b) за кулисами. Это то, как python поддерживает перегрузку оператора, учитывая отсутствие статической типизации.

С# допускает неявное литье в строки с помощью метода ToString(); У python нет понятия неявного литья. Это работает, потому что ToString() - это метод, определенный для каждого объекта, а С# имеет статическую типизацию, поэтому он становится очевидным для вызывающего, когда их объект будет запущен.

Если вы хотите увидеть это поведение в действии, вы можете запустить следующее (но не делайте этого в процессе производства):

class MyString(str):
    def __add__(self, other):
        """ automatically concatenate other values as strings """
        return super(MyString, self).__add__(str(other))

s = MyString("this is a string")
print s + 1

Конечно, если вы посмотрите на приведенное выше преобразование, у вас возникнут проблемы с print 1 + s. Я предлагаю быть явным о вашем преобразовании типов, даже когда просто конвертируем в строку, так как случаи краев будут сбивать вас с ума.