以下是我对java和python中类型和参数传递的理解:在java中,有原始类型和非原始类型。前者不是客体,后者是客体。在python中,它们都是对象。
在java中,参数是按值传递的,因为:原始类型被复制然后传递,所以它们肯定是按值传递的。非原始类型通过引用传递,但引用(指针)也是值,因此它们也通过值传递。在 python 中,唯一的区别是“原始类型”(例如,数字)不会被复制,而只是被当作对象。
根据官方文档,参数通过赋值传递。“通过分配”是什么意思?java中的对象和python的工作方式一样吗?什么导致差异(在java中通过值传递和在python中通过参数传递)?上面有什么错误的理解吗?
aba*_*ert 20
tl;dr:你说得对,Python 的语义本质上是 Java 的语义,没有任何原始类型。
\n\n“通过作业”实际上与您所询问的区别不同。1这个想法是,参数传递给函数(和其他可调用函数)的工作方式与赋值的工作方式完全相同。
\n\n考虑:
\n\ndef f(x):\n pass\na = 3\nb = a\nf(a)\nRun Code Online (Sandbox Code Playgroud)\n\nb = a意味着目标b(在本例中是全局命名空间中的名称)成为对任何值a引用的引用。
f(a)意味着目标x(在本例中是为执行而构建的框架的本地命名空间中的名称f)成为对任何值引用的引用a。
语义是相同的。每当将值分配给目标(并不总是简单的名称\xe2\x80\x94,例如,认为lst[0] = a或spam.eggs = a)时,它都会遵循相同的一组分配规则\xe2\x80\x94,无论它是赋值语句、函数调用、as子句或循环迭代变量,只有一组规则。
但总的来说,您的直觉想法是准确的:Python 类似于 Java,但只有引用类型:您总是“按值传递引用”。
\n\n争论这算作“按引用传递”还是“按值传递”是毫无意义的。试图为它想出一个新的、明确的、没有人会争论的名字更是毫无意义。三十年前,利斯科夫发明了“按对象调用”这个术语,如果这个术语从未流行起来,那么今天人们想出的任何东西都不会做得更好。
\n\n您了解实际的语义,这才是最重要的。
\n\n是的,这意味着没有复制。在 Java 中,仅复制原始值,而 Python 没有原始值,因此不会复制任何内容。
\n\n\n\n\n唯一的区别是“原始类型”(例如数字)不会被复制,而是简单地作为对象
\n
最好将其视为“唯一的区别是没有“原始类型”(甚至不是简单的数字)”,就像您在开始时所说的那样。
\n\n还值得一问的是,为什么 Python 没有原始类型\xe2\x80\x94,或者为什么 Java 有。2
\n\n将所有内容“装箱”可能会非常慢。在 Python 中添加2 + 3意味着取消引用2和3对象,从中获取本机值,将它们加在一起,并将结果包装在一个新5对象中(或者在表中查找它,因为您已经有一个现有5对象)。这比仅仅添加两个整数要多得多的工作。3
虽然像 Hotspot\xe2\x80\x94 或 PyPy for Python\xe2\x80\x94 这样的良好 JIT 通常可以自动执行这些优化,但有时“经常”还不够好。这就是 Java 具有本机类型的原因:让您在这些情况下手动优化。
\n\n相反,Python 依赖于 Numpy 等第三方库,它让您只需为整个数组支付一次装箱成本,而不是为每个元素支付一次。这使得语言更简单,但代价是需要 Numpy。4
\n\n1. 据我所知,“通过分配传递”在常见问题解答中出现了几次,但实际上并没有在参考文档或术语表中使用。参考文档已经倾向于直观而非严谨,但常见问题解答与教程一样,在这个方向上走得更远。因此,除了试图传达的直观想法之外,询问常见问题解答中的术语的含义可能首先就不是一个有意义的问题。
\n\n2. 这里我将忽略Java 缺乏运算符重载的问题。他们没有理由不为少数核心类包含特殊的语言规则,即使他们不允许你对自己的类做同样的事情\xe2\x80\x94例如,Go对于诸如 之类的事情正是这样做的range,而且人们很少抱怨。
3. \xe2\x80\xa6 甚至比循环两个 30 位数字的数组,这就是 Python 实际所做的。与装箱的成本相比,处理无限大小的“bigint”的成本很小,因此 Python 总是付出额外的、几乎不可察觉的成本。Python 2 确实像 Java 一样,有单独的固定类型和 bigint 类型,但几十年的经验表明,它并没有从额外的复杂性中获得任何性能优势。
\n\n4. Numpy 的实现当然远不简单。但使用它非常简单,而且需要使用 Numpy 的人比需要编写 Numpy 的人多得多,所以事实证明这是一个相当不错的权衡。
\n