在学习 C# 时,我发现它很奇怪,动态类型的 Python 会在以下代码中引发错误:
i = 5
print i + " "
而静态类型的 C# 通常会执行类似的代码:
int i = 5;
Console.Write(i + " ");
我希望有其他方式(在python中我可以在没有任何转换的情况下做到这一点,但C#会要求我将int转换为字符串或将字符串转换为int)。
只是为了强调,我不是在问哪种语言更好,我很好奇以这种方式实现语言的原因是什么。
你说得对,这里有些奇怪。奇怪的是,这+
意味着任何一种语言的字符串连接!与完全意味着“连接”的奇怪相比,是否+
可以将 int 连接到字符串上是一个小问题。+
我不知道首先允许+
使用哪种语言来表示字符串连接,但是这种错误功能已经一遍又一遍地重复,以至于现在我们通常甚至没有注意到它有多奇怪。让我们列出一些普通加法的属性,看看字符串是否符合要求。
四分之一不好。字符串连接与加法非常不同,那么它们为什么要共享一个运算符呢?
我不常这么说,但C 说得对。字符串连接运算符应该就是:连接。在 C"X" "Y"
中表示"XY"
. 如果将两个字符串文字并排放置,它们将连接成第三个。
这并不是静态与动态类型的真正领域。相反,它是强类型与弱类型(至少根据维基百科在描述编程语言时也碰巧使用的一些常用术语)。C# 和 Python 都是强类型的(根据该定义)。
不幸的是,所有这些概念都不是黑白的,而是灰度的,并且定义不明确。然而,结果是语言执行类型检查的强度以及它执行的检查存在细微差别。
碰巧的是,在您的特定情况下,C# 重载operator +
了字符串和数字(实际上是任意对象),而 Python 没有。在这种情况下,这可以说使 Python 稍微严格一些。
这不是一个真正的静态/动态问题,而是一个语言设计理念的问题。
在 Python 中,+
定义为数字的加法和字符串的连接。如果您有一点编程经验,这是完全合理的行为。
但是,当您拥有其中一个时,会发生什么?它是尝试将字符串转换为数字,还是将数字转换为字符串?对于任何进行过任何编程的人来说,两者都是完全合理的行为,但是由于不同的语言对如何发生这种情况有不同的规则,你可能会做出与其他人不同的假设,具体取决于你有哪些语言经验已经。
Python 的指导原则之一是“显式优于隐式”(import this
),因此它让您明确说明您想要哪种行为。如何?当然,通过将字符串或数字转换为所需的类型。然后它们都是字符串或都是数字,并且行为很明显。
生成的代码更易于阅读(即使您不太了解 Python),因为您不必猜测它会做什么。
对于 C#,对于(int) 和几乎所有类型都有一个称为ToString()的方法- 在这种情况下,指针类型是例外。Int32
String
C# 中的类重载了+
运算符,在这种情况下,它只是调用String.Concat(Object, Object)。
在我看来,这更多是 .NET Framework 工作的结果,而不是其他任何东西。
了解 Python 数据模型 ( http://docs.python.org/2/reference/datamodel.html#emulating-numeric-types ) 将对您有所帮助。
当您执行时a + b
,这将被转换为a.__add__(b)
幕后。鉴于缺少静态类型,这就是 python 支持运算符重载的方式。
C# 允许通过 ToString() 方法隐式转换为字符串;python 没有任何隐式转换的概念。这是可行的,因为 ToString() 是在每个对象上定义的方法,并且 C# 具有静态类型,因此调用者在他们的对象将被强制转换时是显而易见的。
如果您想查看此行为的实际效果,可以运行以下命令(但不要在生产环境中执行此操作):
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
。我建议明确说明你的类型转换,即使只是转换为字符串,因为边缘情况会让你发疯。
动态类型在这里并没有真正发挥作用,两种语言都理解 i 是一个 int 而 " " 是一个字符串。不同之处在于 C# 有一个函数 + 接受 (int,string) 参数,而 Python 没有。