Почему существует "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
. Я предлагаю быть явным о вашем преобразовании типов, даже когда просто конвертируем в строку, так как случаи краев будут сбивать вас с ума.