参数是通过引用传递还是通过值传递?如何通过引用传递,以便下面的代码输出“Changed”而不是“Original”?

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.change(self.variable)
        print(self.variable)

    def change(self, var):
        var = 'Changed'

另请参阅:为什么函数可以修改调用者感知的某些参数,而不能修改其他参数?


当前回答

我通常使用的一个简单技巧是将其包装在列表中:

def Change(self, var):
    var[0] = 'Changed'

variable = ['Original']
self.Change(variable)      
print variable[0]

(是的,我知道这可能很不方便,但有时这样做很简单。)

其他回答

数据类呢?此外,它允许您应用类型限制(也称为“类型提示”)。

from dataclasses import dataclass

@dataclass
class Holder:
    obj: your_type # Need any type? Use "obj: object" then.

def foo(ref: Holder):
    ref.obj = do_something()

我同意人们的看法,在大多数情况下,你最好考虑不要使用它。

然而,当我们谈论上下文时,我们有必要知道这一点。

不过,您可以设计显式上下文类。在进行原型设计时,我更喜欢数据类,因为来回序列化它们很容易。

干杯

很可能不是最可靠的方法,但这是有效的,请记住,您正在重载内置str函数,这通常是您不想做的事情:

import builtins

class sstr(str):
    def __str__(self):
        if hasattr(self, 'changed'):
            return self.changed

        return self

    def change(self, value):
        self.changed = value

builtins.str = sstr

def change_the_value(val):
    val.change('After')

val = str('Before')
print (val)
change_the_value(val)
print (val)

我使用以下方法将一些Fortran代码快速转换为Python。的确,它不像最初提出的问题那样通过引用传递,但在某些情况下是一个简单的解决方案。

a=0
b=0
c=0
def myfunc(a,b,c):
    a=1
    b=2
    c=3
    return a,b,c

a,b,c = myfunc(a,b,c)
print a,b,c

Effbot(又名Fredrik Lundh)将Python的变量传递风格描述为对象调用:http://effbot.org/zone/call-by-object.htm

对象在堆上分配,指向它们的指针可以在任何地方传递。

当您进行赋值(如x=1000)时,将创建一个字典条目,将当前名称空间中的字符串“x”映射到包含1000的整数对象的指针。当您使用x=2000更新“x”时,将创建一个新的整数对象,并更新字典以指向新对象。旧的一千个对象是不变的(可能还活着,也可能不活着,这取决于是否有任何其他对象指向该对象)。当您执行新的赋值(如y=x)时,将创建一个新的字典条目“y”,该条目指向与“x”条目相同的对象。字符串和整数等对象是不可变的。这仅仅意味着在创建对象之后,没有任何方法可以更改对象。例如,一旦整数对象一千被创建,它将永远不会改变。数学是通过创建新的整数对象来完成的。像列表这样的对象是可变的。这意味着对象的内容可以通过指向该对象的任何对象进行更改。例如,x=[];y=x;x.append(10);打印y将打印[10]。已创建空列表。“x”和“y”都指向同一列表。append方法变异(更新)列表对象(如向数据库添加记录),结果对“x”和“y”都可见(正如数据库更新对数据库的每个连接都可见)。

希望这能为您澄清问题。

除了所有关于Python中这些东西的工作原理的精彩解释之外,我看不到任何关于这个问题的简单建议。就像您创建对象和实例一样,处理实例变量并更改它们的Python方式如下:

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.Change()
        print self.variable

    def Change(self):
        self.variable = 'Changed'

在实例方法中,通常引用self来访问实例属性。在__init__中设置实例属性并在实例方法中读取或更改它们是正常的。这也是为什么将self-als作为第一个参数传递给def Change。

另一种解决方案是创建如下静态方法:

class PassByReference:
    def __init__(self):
        self.variable = 'Original'
        self.variable = PassByReference.Change(self.variable)
        print self.variable

    @staticmethod
    def Change(var):
        var = 'Changed'
        return var