如何处理Python~静态类型?

Eta*_*tam 11 python java static-typing dynamic-typing

我来自Java世界,我想知道在编译代码时除了缺少错误外,Python中的动态类型有什么好处?

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

Jör*_*tag 18

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

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

这通常适用于所有静态类型,而不仅仅适用于Java.

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

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

String[] a = new String[1];
Object[] b = a;
b[0] = 1; // ArrayStoreException
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

def fib(n):
    if n < 2: return n
    return fib(n-2) + fib(n-1)
Run Code Online (Sandbox Code Playgroud)

和Java:

int fib(int n) {
    if (n < 2) return n;
    return fib(n-2) + fib(n-1);
}
Run Code Online (Sandbox Code Playgroud)

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

def fib(n: int) -> int:
    if n < 2: return n
    return fib(n-2) + fib(n-1)
Run Code Online (Sandbox Code Playgroud)

[有意思的是:与另外在Python 3.x的可选静态类型的注解,那就是实际上也是有效的Python代码,但它显然还没有静态的类型安全的,因为注释只是:注解.他们从未在任何地方进行实际检查.

还有就是一些明确的杂波出现.但是,在Haskell中它看起来像这样:

fib n
  |     n < 2 = n
  | otherwise = fib (n-2) + fib (n-1)
Run Code Online (Sandbox Code Playgroud)

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

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

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

fib 0 = 0
fib 1 = 1
fib n = fib (n-2) + fib (n-1)
Run Code Online (Sandbox Code Playgroud)

或这个:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Run Code Online (Sandbox Code Playgroud)

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

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

  • +1,我可以建议你的帖子的整体反Java(甚至反BASIC)主题变得轻松吗?它提出了令人信服的论据,但是使用像'糟糕'这样的表达方式,'孔太大以至于你可以驾驶卡车','只是不是一个好的编程语言'并没有真正为已经很好的答案添加任何东西. (6认同)
  • @ssokolow:是的,没错.请注意,C#3和C++ 0x实际上通过类型推断提供了隐式类型,尽管在这两种情况下你实际上都必须*明确*告诉他们分别通过`var`和`auto`关键字使用*implicit*typing. (3认同)

Dav*_*rby 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语言存在缺陷,需要使用外部工具进行补偿.


S.L*_*ott 5

Do you like it in Python?

It's part of Python. Liking it in Python is silly.

Do you have an example where it helped in a big project?

Yes. Every single day I rejoice that I can make changes and -- because of Duck typing -- they are reasonably localized, pass all the unit tests, pass all the integration tests, and nothing is disrupted elsewhere.

If this was Java, the changes would require endless refactoring to pull interfaces out of classes so that I could introduce variations that were still permitted under Java's static type checking.

Doesn't it a bit error prone?

Not any more than static typing is. A simple unit test confirms that the objects conform to the expected features.

It's easy to write a class in Java that (a) passes compile-time checks and (b) crashes horribly at run time. Casts are a good way to do this. Failing to meet the classes intent is a common thing -- a class may compile but still not work.


Hum*_*art 0

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

它使代码更简单。