Python类实例的函数传递机制:传引用还是传值?
Python类实例传递给函数的机制与行为解析
核心本质:Python的参数传递是「传对象引用」
Python里所有变量本质都是对象的引用。当你把变量传给函数时,实际上是把这个引用的副本传给了函数的形参。也就是说,函数内的形参和外部的实参最初指向同一个对象,但形参本身是局部变量——如果给形参重新赋值,只是让这个局部变量指向另一个对象,完全不会影响外部实参的指向。
为什么第一段代码输出dog?
看你这段代码:
def change_animal(animal_1, animal_2): animal_1 = None # 局部变量animal_1改为指向None,和外部的animal_1彻底无关 animal_1 = animal_2 # 局部变量指向animal_2的对象,外部的animal_1仍指向原来的dog实例
外部的animal_1自始至终都指向最初创建的Animal('dog', 'bark')对象,函数里的操作只是修改了局部变量的指向,所以最后打印结果还是dog。
为什么第二段代码输出duck?
这段代码里你没有给形参animal_1重新赋值,而是直接修改了它指向的对象的属性:
def change_animal(animal_1, animal_2): animal_1.name = animal_2.name animal_1.sound = animal_2.sound
因为函数内的animal_1和外部的animal_1指向同一个对象,修改对象的属性会直接反映到外部,所以最后打印结果是duck。
避免逐个赋值属性的实用方法
如果你不想手动逐个复制属性,可试试以下几种方案:
1. 利用__dict__批量更新属性
Python对象的自定义属性(未用__slots__限制的)都存在__dict__字典中,直接用update方法就能批量复制:
def change_animal(animal_1, animal_2): animal_1.__dict__.update(animal_2.__dict__)
这样能一次性把animal_2的所有属性复制到animal_1,不用逐个写赋值语句。
2. 返回新实例,外部重新赋值
如果不想修改原有对象,而是让外部变量指向新实例,可让函数返回新对象,再在外部重新赋值:
import copy def change_animal(animal_2): # 浅拷贝(如果属性都是不可变类型够用) # return Animal(animal_2.name, animal_2.sound) # 深拷贝(适合属性包含可变对象的场景) return copy.deepcopy(animal_2) # 外部调用 animal_1 = change_animal(animal_2)
这种方式逻辑更清晰,尤其适合线程等复杂场景,能避免共享对象带来的并发问题。
3. 给类添加复制方法
在Animal类中定义一个复制方法,后续新增属性时只需修改这个方法:
class Animal: def __init__(self, name, sound): self.name = name self.sound = sound def copy_from(self, other): self.name = other.name self.sound = other.sound # 以后加新属性,只需要在这里追加一行 # 调用时直接调用实例方法 animal_1.copy_from(animal_2)
这种方法比手动逐个赋值更易维护,不用修改所有调用的地方。
内容的提问来源于stack exchange,提问作者Tommy Wolfheart
相关产品推荐
相关产品推荐

