Python中传递引用

最近依然用Python在填坑之前提到的小游戏项目,遇到了一个问题,先看代码:

packet_sender = PacketSender('localhost', 2333, client_var=ClientThreadVar)

这里新声明了一个PacketSender的实例对象packet_sender, 其中指定了一个参数client_varClientThreadVar,而ClientThreadVar是一个全局对象,程序运行过程中会有其他线程对其进行读写,作为一个C++忠实选手我开始对最后一个参数的传递出现了怀疑,ClientThreadVar究竟是以引用传递的还是以值传递的?

弄明白这个问题,我们可以写一点测试代码:

class MyClass:
    def __init__(self, **kwargs):
        self.var = kwargs.get('var', None)

    def changeVar(self):
        self.var = 23333


x = 56
myclass = MyClass(var=x)
myclass.changeVar()
print("x = {}".format(x))
print("myclass.var = {}".format(myclass.var))

没错,这个代码的结果是x仍然是56,而myclasss.var的值毫无疑问的是2333。

这样是否说明类似于这样的传参是以值的形式传递的?不妨来看下面的代码:

class MyObj:
    def __init__(self, x):
        self.x = x


class MyClass2:
    def __init__(self, **kwargs):
        self.var = kwargs.get('var', None)

    def changeVar(self):
        self.var.x = 9999

obj = MyObj(233333)
myclass2 = MyClass2(var=obj)
myclass2.changeVar()
print("obj.x = {}".format(obj.x))
print("myclass2.var.x = {}".format(myclass2.var.x))

然而结果让我们大跌眼镜,不管是obj.x还是myclass2.var.x的值都变成了9999。也就是说这里的obj是以引用的形式传递的。

为什么不同类型的参数,一样的传递方法却是通过不同的传递方式实现的?秉承着“我要系统学习python”的想法,了解为什么在Python中会出现这种情况。

原因

在Python中,参数是以值的方式传递的。但是,Python中没有所谓的”变量”,有的只有对象的引用。除此之外,有一些类型的他是可变的,而有一些是不可变的。

什么意思?

比如我们在第一个测试中写下的x = 56,他并不是一个声明了一个int变量,赋值56;而是产生了一个对象,值是56,而x是这个对象的引用。我们把x传递给var,实际上我们是新建了一个引用var指向同样的对象56。到这里还没啥问题,但是,这里的x是int,他是不可变的。也就是说,我们将2333赋值给var的时候,并不是将var指向的对象的值从56改成2333,而是将var重新指向一个新的对象,值是2333。

但是对第二个测试中的obj就不一样了,objx最大的差别就是obj是可变的,而x是不可变的。我们再次分析一遍测试二obj的传递过程,首先我们创建了一个MyObj对象,obj是这个MyObj对象的引用。同时,我们也创建了一个MyClass2对象,myclass2是他的引用。我们将obj传递给var,此时的过程和测试一是一样的,这时候varobj都指向同一个对象。接下来调用changeVarvar进行修改,此时因为varobj都指向同一个类对象,是可变的,所以修改的是对象本身。

总结

就我自己的经验,一般python都会如自己所想的运行,而不像某些语言总是做些幺蛾子出来。不过u1s1,python语法真的是比较恶心

2019-2020 Sunshine+Ice