【问题标题】:what does it mean by 'passed by assignment'?“通过分配”是什么意思?
【发布时间】:2018-05-25 17:40:11
【问题描述】:

以下是我对java和python中类型和参数传递的理解: 在java中,有原始类型和非原始类型。前者不是对象,后者是对象。 在python中,它们都是对象。

在java中,参数是按值传递的,因为: 原始类型被复制然后传递,因此它们肯定是按值传递的。非原始类型通过引用传递,但引用(指针)也是值,所以它们也是通过值传递的。 在python中,唯一的区别是“原始类型”(例如,数字)不是复制的,而是简单地作为对象。

基于官方文档,参数通过赋值传递。 “通过分配”是什么意思? java中的对象和python的工作方式一样吗?什么导致了差异(在java中通过值传递并在python中通过参数传递)? 而且上面有什么错误的理解吗?

【问题讨论】:

  • Brandon Rhodes 的这次演讲涵盖了这一点以及更多关于名称和引用如何在 Python 中工作的内容:(Video) Names, Objects, and Plummeting From The Cliff。一旦您了解了将 object references 绑定到 names 的工作原理,其他一切都会到位。一旦您对此有了直观的理解,您只需要知道哪些类型是可变的,哪些不是。 “按值传递”与“按引用传递”的问题真正成为一个有争议的问题。

标签: python


【解决方案1】:

tl;dr:你说得对,Python 的语义本质上是 Java 的语义,没有任何原始类型。


“通过赋值传递”实际上与您所询问的区别不同。1 这个想法是传递给函数(和其他可调用对象)的参数的工作方式与赋值完全相同有效。

考虑:

def f(x):
    pass
a = 3
b = a
f(a)

b = a 表示目标b,在本例中为全局命名空间中的名称,成为对a 引用的任何值的引用。

f(a) 表示目标x,在这种情况下是为执行f 而构建的框架的本地命名空间中的名称,成为对a 引用的任何值的引用。

语义相同。每当一个值被分配给一个目标时(这并不总是一个简单的名称——例如,认为lst[0] = aspam.eggs = a),它遵循相同的赋值规则集——无论是赋值语句、函数调用还是as 子句,或者循环迭代变量,只有一组规则。


但总的来说,您认为 Python 与 Java 类似但只有引用类型的直观想法是准确的:您总是“按值传递引用”。

争论这算作“按引用传递”还是“按值传递”是没有意义的。试图为它想出一个没有人会争论的新的明确名称是更没有意义的。 Liskov 在 30 年前发明了 "call by object" 这个词,如果它从未流行起来,那么今天有人想出的任何东西都不太可能做得更好。

您了解实际的语义,这才是最重要的。


是的,这意味着没有复制。在 Java 中,只复制原始值,而 Python 没有原始值,因此不会复制任何内容。

唯一的区别是“原始类型”(例如,数字)不会被复制,而只是被视为对象

最好将其视为“唯一的区别是没有没有'原始类型'(甚至不是简单的数字)”,正如您在开始时所说的那样。


还值得一问,为什么 Python 没有原始类型——或者为什么 Java 有。2

将所有内容“装箱”可能会非常缓慢。在 Python 中添加 2 + 3 意味着取消引用 23 对象,从中获取本机值,将它们相加,并将结果包装在新的 5 对象中(或在表中查找)因为您已经有一个现有的5 对象)。这比仅仅添加两个整数要多得多。3

虽然像 Hotspot 或 Python 的 PyPy 这样的良好 JIT 通常可以自动执行这些优化,但有时“经常”还不够好。这就是 Java 具有原生类型的原因:让您在这些情况下手动优化事物。

相反,Python 依赖于 Numpy 等第三方库,它让您只需为整个数组支付一次装箱成本,而不是每个元素一次。这使语言更简单,但代价是需要 Numpy。4


1。据我所知,“通过分配”在常见问题解答中出现了几次,但实际上并未在参考文档或词汇表中使用。参考文档已经倾向于直观而不是严谨,但常见问题解答和教程一样,朝着这个方向走得更远。因此,询问常见问题解答中的一个术语是什么意思,超出了它试图传达的直观概念,首先可能不是一个有意义的问题。

2。我将在这里忽略 Java 缺少运算符重载的问题。没有理由他们不能为少数核心类包含特殊的语言规则,即使他们不允许你对自己的类做同样的事情——例如,Go 对 range 和人们做的事情就是这样很少抱怨。

3。 ……甚至不是循环两个 30 位数字的数组,这正是 Python 实际所做的。与装箱的成本相比,处理无限大小的“bigint”的成本微乎其微,因此 Python 总是支付额外的、几乎不引人注意的成本。 Python 2 确实像 Java 一样具有单独的固定类型和大整型类型,但几十年的经验表明,它并没有从额外的复杂性中获得任何性能优势。

4. Numpy 的实现当然远非简单。但是使用它非常简单,需要使用 Numpy 的人比需要编写 Numpy 的人多得多,因此这是一个相当不错的权衡。

【讨论】:

    【解决方案2】:

    类似于在 C# 中按值传递引用类型。

    文档:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-reference-type-parameters#passing-reference-types-by-value

    代码演示:

    # mutable object
    l = [9, 8, 7]
    
    
    def createNewList(l1: list):
        # l1+[0] will create a new list object, the reference address of the local variable l1 is changed without affecting the variable l
        l1 = l1+[0]
    
    
    def changeList(l1: list):
        # Add an element to the end of the list, because l1 and l refer to the same object, so l will also change
        l1.append(0)
    
    
    print(l)
    createNewList(l)
    print(l)
    changeList(l)
    print(l)
    
    # immutable object
    num = 9
    
    
    def changeValue(val: int):
        # int is an immutable type, and changing the val makes the val point to the new object 8, 
        # it's not change the num value
        value = 8
    
    
    print(num)
    changeValue(num)
    print(num)
    

    【讨论】:

      猜你喜欢
      • 2015-03-16
      • 2019-11-03
      • 2016-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-29
      • 1970-01-01
      • 2015-03-26
      相关资源
      最近更新 更多