一种Pythonic方法,用于更改传递到函数中的内容的值,并使该更改在函数外部保持不变

一种Pythonic方法,用于更改传递到函数中的内容的值,并使该更改在函数外部保持不变,python,immutability,Python,Immutability,有时我想将一个对象传递给一个函数,并让该函数更改原始对象的值。如果我使用C++,我会通过引用。在python中有哪些不同的方法可以做到这一点,推荐的方法是什么,为什么没有一种简单的方法(比如在C++中通过引用传递)来做到这一点 证明: from enum import IntEnum class Bar(IntEnum): A=0 B=1 C=2 def mutate(b: Bar): b = Bar.B # b is immutable. It does n

有时我想将一个对象传递给一个函数,并让该函数更改原始对象的值。如果我使用C++,我会通过引用。在python中有哪些不同的方法可以做到这一点,推荐的方法是什么,为什么没有一种简单的方法(比如在C++中通过引用传递)来做到这一点

证明:

from enum import IntEnum

class Bar(IntEnum):
    A=0
    B=1
    C=2

def mutate(b: Bar):
    b = Bar.B # b is immutable. It does not change the value of the b parameter, instead it rebinds, and becomes a new Bar.B

if __name__ == '__main__':
    b=Bar.A
    print(b) # prints Bar.A
    mutate(b)
    print(b) # still prints Bar.A
在本例中,您可能希望第二个
print(b)
输出
Bar.b
,但它仍然是
Bar.A
,因为mutate函数本质上是说“b可以忘记它以前绑定到的内容,而现在它绑定到这个Bar.A”

如果b是一个列表或另一个可变类型,您仍然可以附加到它,并且该更改将在函数之外保持,因为列表是可变的


但是,如果我想在函数内部更改不可变类型的值,并在函数外部保留该更改,我该怎么办

一种解决方案是将其包装在类中,因为类是可变的:

from enum import IntEnum
from typing import Generic, TypeVar

class Bar(IntEnum):
    A=0
    B=1
    C=2

T=TypeVar('T')
class Mutable(Generic[T]):
    def __init__(self, data: T):
        self.data = data

def mutate(b: Mutable[Bar]):
    b.data = Bar.B # b is mutable. The change to the b parameter will persist outside of this function

if __name__ == '__main__':
    b=Mutable(Bar.A)
    print(b.data) # prints Bar.A
    mutate(b)
    print(b.data) # prints Bar.B
但是有东西告诉我,如果这是一个好主意,那么它就已经在python标准库中了。那为什么这不是个好主意呢?那么,什么是获得我想要的行为的推荐方法


谢谢

为什么不干脆
b=mutate(b)
并在函数中返回
b
?“并让该函数更改原始对象的值”没有什么可以阻止您更改对象,除非它是不可变的。您需要通过引用进行调用,这在Python中是不可能的。你不能以你想要的方式来模拟它。“但是,如果我想在函数中更改不可变类型的值,并让这种更改在函数之外持久化,我该怎么办?”你不能这样定义。@Asocia说的是Python的方式。您不会编写改变另一个作用域状态的代码。即使你可以,想象一下,如果别人的代码实现了
mutate
,而你没有意识到这一点,那将是多么糟糕。“x=1怎么可能?我把它设置为x=2!它不可能是1!”@Blue7柯克·斯特劳斯说的是,不要将代码设计为使用引用调用。它没有增加任何优势,在Fortran/C++中至少有一个性能优势,但它会导致各种混乱的代码。正如ascosia建议的那样,
m=foo(m)
更有意义。调用方的命名空间不应由函数修改。在现代语言中,你很少看到引用调用,这是一个原因。为什么不在你的函数中返回变异后的值
b
?“并让该函数更改原始对象的值”没有什么可以阻止你改变对象,除非它是不可变的。您需要通过引用进行调用,这在Python中是不可能的。你不能以你想要的方式来模拟它。“但是,如果我想在函数中更改不可变类型的值,并让这种更改在函数之外持久化,我该怎么办?”你不能这样定义。@Asocia说的是Python的方式。您不会编写改变另一个作用域状态的代码。即使你可以,想象一下,如果别人的代码实现了
mutate
,而你没有意识到这一点,那将是多么糟糕。“x=1怎么可能?我把它设置为x=2!它不可能是1!”@Blue7柯克·斯特劳斯说的是,不要将代码设计为使用引用调用。它没有增加任何优势,在Fortran/C++中至少有一个性能优势,但它会导致各种混乱的代码。正如ascosia建议的那样,
m=foo(m)
更有意义。调用方的命名空间不应由函数修改。在现代语言中,你很少看到通过引用调用是有原因的。