Python中传递引用
最近依然用Python在填坑之前提到的小游戏项目,遇到了一个问题,先看代码:
packet_sender = PacketSender('localhost', 2333, client_var=ClientThreadVar)
这里新声明了一个PacketSender
的实例对象packet_sender
, 其中指定了一个参数client_var
为ClientThreadVar
,而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
就不一样了,obj
和x
最大的差别就是obj
是可变的,而x
是不可变的。我们再次分析一遍测试二obj
的传递过程,首先我们创建了一个MyObj
对象,obj
是这个MyObj
对象的引用。同时,我们也创建了一个MyClass2
对象,myclass2
是他的引用。我们将obj
传递给var
,此时的过程和测试一是一样的,这时候var
和obj
都指向同一个对象。接下来调用changeVar
对var
进行修改,此时因为var
和obj
都指向同一个类对象,是可变的,所以修改的是对象本身。
总结
就我自己的经验,一般python都会如自己所想的运行,而不像某些语言总是做些幺蛾子出来。不过u1s1,python语法真的是比较恶心