可变和不可变类型背后的理论是什么?

18

我钦佩 Python 的一点是它区分可变和不可变类型。在使用 Python 之前,我曾花了一些时间在 C 语言编程,惊讶于 Python 很容易地消除了在 C 语言中令我疯狂的指针解引用的复杂性。在 Python 中,一切都按照我期望的方式工作,我很快意识到可变/不可变的区别在其中发挥了重要作用。

当然,还有一些细节需要考虑(可变函数参数默认值是一个显著的例子),但总体而言,我觉得可变/不可变的区别极大地澄清了关于变量及其值是什么以及它们应该如何行事的问题。

但是这个区别从哪里来?我必须假设 GvR 不是第一个构思这种区别的人,Python 也不是第一个使用它的语言。我对早期使用这个概念的语言以及任何早期的理论讨论感兴趣。

4个回答

7

如果你喜欢不可变性的想法,你应该尝试一下纯函数式语言。在Haskell中,所有(纯)变量都是不可变的(但仍被称为“变量”,但这就是它)。这是一个很好的想法 - 你和编译器都知道将某些东西传递到函数中不能以任何方式改变它。


是的,我现在正在学习 Haskell -- 实际上我认为这就是让我有这个想法的原因! - jsau

5
在C语言中,没有显式的不可变概念,因为该语言基于复制语义。而在Python中,值始终通过引用传递,不可变性在保持语言可管理性方面起着重要作用。
在Python中,不存在指针,因为实际上一切都是指针!想象一下,如果Python程序中甚至可以更改数字对象的值,那么你将被迫使用诸如...这样的技巧。
class Shape:
    def __init__(self, points):
        self.points = points[:] # make a copy of the list

不仅适用于列表和字典,还适用于数字值和字符串。
因此,在Python中,某些类型具有不可变实例,因为它们通常被用作“值”,您不关心身份。在需要例如带有数字值的可变对象的罕见情况下,您需要明确地将其包装在类实例中。
在其他基于引用语义(如LISP)的语言中,不可变性是留给程序员的选择,而不是约束,即使许多函数和习惯用法都支持它(大部分LISP标准库函数都是非破坏性的,这实际上有点遗憾,因为破坏性函数并不总是通过名称清晰可辨)。
因此,例如,在LISP中,字符串是可变的,但可能没有多少LISP程序实际上会就地修改字符串,因为那意味着放弃漂亮的共享可能性,并且需要在许多地方显式复制字符串(在大多数情况下,字符串只是值,而不是您关心身份的对象)。LISP中的字符串是否不可变?不。程序是否对其进行突变?几乎从不。
不给程序员留下选择是Python语言的精神。当你被迫做出与你的想法一致的选择时,感觉很棒...决策更少,事情正好像你想要的那样。
然而,在我看来,这种方法有两个不同的危险:
1. 当这些预制选择与您想要或需要做的内容不一致时,问题会出现。Python是一种美妙的语言,但是如果有一个不同的独裁者,它可能变成纯粹的地狱。 2. 理解和做出选择强迫您思考并扩展您的思维。不做出选择只会在您的思维上设置一个笼子,过了一段时间,您甚至可能意识不到您正在使用的只是一种可能性,而不是唯一的可能性。过了一段时间,您可能开始认为“必须以这种方式完成事情”:您甚至没有感到被迫,因为您的思维已经被“切割”。

4

Objective C充满了可变/不可变的区别(例如,有NSStringNSMutableString);它比Python早约8年。Smalltalk是Objective C继承其面向对象设计的主要来源之一,但使用这个概念的程度较小(值得注意的是,字符串不是不可变的;如今的趋势是使用像Python、Ruby等不可变字符串)。


关于Objective C的内容很有趣。我需要更加了解它。谢谢! - jsau

-2

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