为什么Python不能像Scala一样推断类型?

15

可能重复问题:
如何处理Python静态类型?

我基本上是一名Java程序员,对Python的了解很少。我非常喜欢Python的语法和程序员能够表达自己想法的简易性,但我也知道Python是动态类型的,因此不像Java那样快速。我的问题是为什么Python不能像Scala等语言一样推断类型呢?


4
Scala有类型,只是你不必一直打出它们(这句话有双关意味)。 - Thilo
1
我认为那不是重复的问题。另一个问题更多地涉及“为什么Python根本不需要类型”。 - Thilo
1
@Emil:为什么每个人都希望所有编程语言看起来都一样? - pyfunc
1
@pyfunc: Emil并没有问如何改变Python的外观。他只是想知道为什么不进行类型推断(这可能会导致更好的编译时错误检查和改进的性能)。 - Thilo
2
虽然在许多常见应用程序中,Python通常不如Java快,但我看不出这与静态和动态类型有什么关系。 - MAK
显示剩余4条评论
3个回答

27

Python可以做到,但它不这样做。区别在于语言设计者选择遵循的类型系统。

Python使用鸭子类型和具有类型的对象,但变量名不带类型。类型限制不是在编译时检查的;相反,对一个对象的操作可能失败,表明该对象不是合适的类型。尽管是动态类型语言,但Python是强类型的,禁止不明确定义的操作(例如将数字加入字符串),而不是试图默默地理解它们。

Scala是一种静态类型语言,即在编译时检查类型。本地类型推断机制确保用户不需要用冗余的类型信息注释程序。违反类型约束的操作会导致编译器错误,而不是运行时错误。还请参阅Scala类型系统的目的,特别是讨论鸭子类型的部分。


有一些Python编译器可以自动推断类型,例如RPython。这仅仅是因为RPython是Python的静态类型子集。 - Anderson Green
尝试使用doctests来理解程序,如果不行,可以尝试这个:http://chrislaffra.blogspot.com/2016/12/auger-automatic-unit-test-generation.html - aoeu256
还有一些Python库可以在运行时推断函数的类型,例如MonkeyType - Anderson Green

3

Python不进行静态类型推断,因为它希望让你做一些在这种方案下不可能的事情。例如:

def myfn():
  if random.random() > 0.5
    return "howdy"
  else:
    return 7

x = myfn() #  Am I a string or an integer?

x的类型应该是什么?

编辑:示例为:

def myfn(x):
  try:
    return str(x[0]+1) + " is my favourite"
  catch IndexError:
    return x+1

myfn(1) #  = 2
myfn( [2,4,6] ) # = "3 is my favourite"

1
嗯...它可以生成两个幕后函数:Sequence -> str(或者可能是Sequence -> Sequence)和int -> int。有点像重载。 - Ionuț G. Stan
1
def myfn(x: Array[Int]) = try Left(str(x(0) + 1) catch { case e: ArrayIndexOutOfBoundsException => Right(x + 1) - Ricky Clarkson
3
不可能吗?def myfn = if (util.Random.nextBoolean) "rowdy" else 7; val x = myfn <-- 这是完全有效的Scala。 - Daniel C. Sobral
@Michael Anderson:但是在对结果进行任何操作之前,您需要动态检查其类型,那么相比始终返回一个数组并检查大小,您获得了什么? - Tom Crockett
1
@Michael 返回类型确实是 Any,Scala 不会让你对其进行任何操作,除非你匹配其类型或将其强制转换。不同之处在于,Scala 不会让你调用方法,除非它在编译时知道对象支持该方法,而 Python 则允许你调用任何方法,其适用性只有在运行时才能确定。使用动态类型语言就像对编译器说“相信我,我知道我在做什么。”使用静态类型语言就像说“检查一下,看我是否正确。” - Daniel C. Sobral
显示剩余10条评论

-2

Python是动态类型语言,而类型推断只可能在静态类型语言中实现。如果不放弃支持任意对象列表等功能,就不可能实现静态类型。


1
@Thilo: "x = 123; x = str(x); x = [c for c in x]" , x 是整数、字符串还是列表? - Lie Ryan
1
@Lie Ryan,我猜编译器可以重写标识符的名称,以便它们可以共存。x_int = 123; x_str = str(x_str); x_list = [c for c in x_str] - Ionuț G. Stan
1
@Ionuț G. Stan:假设编译器这样做了,你会如何重写 x = 123 # 假设这是来自函数参数if x in [123, '234']: x = '123'else: x = ['2', '3', '4']print x if '3' in x else 'no 3';重新将其转换为静态类型名称会变得非常混乱。 - Lie Ryan
1
@Thilo:Psyco在运行时执行一种有限的类型推断。它基本上检测对象的类型,根据该类型假设重新编译Python为x86指令,然后将编译后的代码注入正在运行的代码中,并添加一些类型检查以确保不违反类型推断;如果类型推断被违反,可能会发生两件事情:Python版本将被调用或Psyco将使用第二个类型假设生成第二个编译代码版本。 - Lie Ryan
类型推断并不等同于静态类型。在动态类型语言中完全可以进行类型推断。例如,如果您有一块代码 x = 3,而且没有其他地方涉及到 x,那么 x 绝对是一个整数。当然,您可以应用更复杂的规则,但这就是这个想法。 - Michael Mior
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接