如何处理Python~静态类型?

时间:2010-09-01 19:07:32

标签: java python static-typing dynamic-typing

我来自Java世界,我想知道Python中动态类型的优点是什么,除了在编译代码时遗漏错误?

你喜欢Python的打字吗?你有一个例子,它在一个大项目中有所帮助吗?是不是有点容易出错?

7 个答案:

答案 0 :(得分:18)

在一般情况下,静态类型检查是不可判定的。这意味着有些程序是静态类型安全的,但类型检查程序不能证明它们是静态类型安全的,因此类型检查器必须拒绝这些程序。

换句话说:类型检查程序不允许您编写类型安全程序。或者,更简洁:静态类型阻止您编写某些程序。

这一般适用于所有静态类型,而不仅仅适用于Java。

至于Java:它有一个相当糟糕的类型系统。它的类型系统表达能力甚至不足以表达 very 简单属性。例如:在static void java.util.Arrays.sort(Object[] a)的类型中,它实际上说结果必须是,你知道,排序了吗?或者数组元素必须部分排序?

Java的另一个问题是它的类型系统有很大的洞,你可以驾驶卡车通过:

String[] a = new String[1];
Object[] b = a;
b[0] = 1; // ArrayStoreException

这种特殊情况下的问题是协变数组。数组根本不可能是协变的和类型安全的。

Java结合了静态类型的所有麻烦,没有任何优势。所以,你也可以摆脱麻烦。

然而,请注意,这不是普遍的。还有其他语言有更好的类型系统,这些系统的权衡不太清楚。

例如,这是Python中有史以来最愚蠢的语言基准(Fibonacci):

def fib(n):
    if n < 2: return n
    return fib(n-2) + fib(n-1)

和Java:

int fib(int n) {
    if (n < 2) return n;
    return fib(n-2) + fib(n-1);
}

请注意,那里存在更多混乱,这与静态类型有关。为了使比较更公平,让我们想象一下使用Python语法和Java语义的语言:

def fib(n: int) -> int:
    if n < 2: return n
    return fib(n-2) + fib(n-1)

[有趣的注意:在Python 3.x中添加了可选的静态类型注释, 实际上也是有效的Python代码,尽管它显然仍然不是静态类型安全的,因为注释只是:注释。它们实际上从未在任何地方进行过检查。]

那里有一些明确的混乱。但是,在Haskell中它看起来像这样:

fib n
  |     n < 2 = n
  | otherwise = fib (n-2) + fib (n-1)

与Python版本不同,这个 完全是静态类型安全的,但没有与类型相关的混乱。

在这种特殊情况下,静态和动态类型的好处之间的问题不太清楚。

顺便说一句,更惯用的Haskell版本可能看起来像这样:

fib 0 = 0
fib 1 = 1
fib n = fib (n-2) + fib (n-1)

或者这个:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

实际上,Java和Python之间更重要的区别并不在于Java是静态类型的,而是动态类型化的Python,而是Java不是一种优秀的编程语言,而Python 。所以,Java总是会失败,不是因为它是静态类型的,而是因为它是垃圾。比较BASIC和Haskell,Haskell明显胜出,但同样,不是因为它是静态类型的,而是因为BASIC是垃圾。

更有趣的比较是Java vs. BASIC或Python vs. Haskell。

答案 1 :(得分:12)

我怀疑绝大多数非平凡的Java程序都有动态类型。

每次在Java中,您都要从Object转换为显式类型,而您正在进行动态类型检查 - 这包括在1.5中引入泛型之前对集合类的每次使用。实际上,Java泛型仍然可以将某些类型检查推迟到运行时。

每次使用Java反射时,都会进行动态类型检查。这包括从文本文件中的类或方法名称到真实类或方法的映射 - 例如每次使用Spring XML配置文件时。

这是否会使Java程序变得脆弱且容易出错? Java程序员是否花费大量时间来跟踪和修复错误动态类型的问题?可能不是 - 也不是Python程序员。

动态类型的一些优点:

  • 大大减少对继承的依赖。我见过带有大量继承树的Java程序。 Python程序通常使用很少或没有继承,更喜欢使用duck typing。
  • 编写真正通用的代码很容易。例如,min()和max()函数可以采用任何类似类型的序列 - 整数,字符串,浮点数,具有适当比较方法,列表,元组等的类。
  • 更少的代码。很大一部分Java代码对解决手头的问题没有任何帮助 - 纯粹是为了保持类型系统的快乐。如果Python程序的大小是等效Java程序的五分之一,则编写,维护,读取和理解的代码只有五分之一。换句话说,Python具有更高的信噪比。
  • 更快的开发周期。这与更少的代码密切相关 - 您花在思考类型和类上的时间更少,并且花更多的时间考虑解决您正在处理的问题。
  • 很少需要AOP。我认为Python有面向方面的库,但我不知道有谁使用它们,因为你需要AOP的99%可以用装饰器和动态对象修改。 AspectJ在Java世界中的广泛使用向我表明,核心Java语言存在缺陷,需要使用外部工具进行补偿。

答案 2 :(得分:5)

  

你喜欢Python吗?

它是Python的部分。喜欢 in Python是愚蠢的。

  

你有一个例子,它在一个大项目中有所帮助吗?

是。每一天我都高兴我可以做出改变 - 因为Duck打字 - 他们合理地本地化,通过所有单元测试,通过所有集成测试,没有在其他地方被打乱。 / p>

如果这是Java,那么更改将需要无休止的重构以从类中提取接口,以便我可以引入在Java的静态类型检查下仍然允许的变体。

  

是不是有点容易出错?

不仅仅是静态输入。简单的单元测试确认对象符合预期的特征。

用Java编写一个类很容易(a)通过编译时检查,(b)在运行时崩溃。演员阵容是一个很好的方法。未能满足 intent 类是常见的事情 - 类可以编译但仍然不能工作

答案 3 :(得分:2)

许多模式(例如来自GoF)是不必要的,或者可以用具有功能性风格的动态类型语言中的较少努力来实现。实际上,很多模式都是“内置”到python中的,所以如果你编写短代码和“pythonic”代码,你将获得免费的所有好处。您不需要Iterator,Observer,Strategy,Factory Method,Abstract Factory以及Java或C ++中常见的一堆其他模式。

这意味着更少的代码可以编写,而且(更重要的是)更少的代码可供阅读,理解和支持。我认为这是像python这样的语言的主要好处。在我看来,这大大超过了静态类型的缺失。类型相关的错误通常不在python代码中,并且很容易用简单的功能测试来捕获(这样的测试在python中比在java中更容易编写)。

答案 4 :(得分:0)

这是你的想法。您可以将红色视为“红色”(常量)为“255,0,0”(元组)或“#FF0000”(字符串):三种不同的格式,需要三种不同的类型,或复杂的查找和Java中的转换方法。

它使代码更简单。

答案 5 :(得分:0)

  

例如,您可以编写函数   您可以将整数传递给   以及字符串或列表或   字典或其他任何东西,它   将能够透明地处理   所有这些都以适当的方式(或   如果它无法处理则抛出异常   类型)。你可以做那样的事情   在其他语言中,但通常   你必须诉诸(ab)使用东西   像指针,引用或   类型转换,打开漏洞   编程错误,它只是   简单丑陋。

答案 6 :(得分:0)

当你来自Java世界时,显而易见的答案是,不要强迫你写下你被迫编写的所有东西,只是为了让Java的类型系统感到高兴。

当然,还有其他静态类型检查的语言不会强迫你写出Java强迫你写的所有内容。

即使是C#也会对本地方法变量进行类型推断!

还有其他静态类型检查语言提供比Java提供的更多编译时错误检查。

(不太明显的答案 - 在Python中动态类型的优点是什么? - 可能需要更多地了解Python才能理解。)