产品销售型企业网站,网站备案需要什么东西,济南哪家网站技术比较高,网站开发制作熊掌号学习python的第十三天之数据类型——函数传参中的传值和传址问题
函数传参中的传值和传址问题 函数传参的机制可以理解为传值#xff08;pass-by-value#xff09;和传址#xff08;pass-by-reference#xff09;的混合体#xff0c;但实际上更接近于传对象引用#xff…学习python的第十三天之数据类型——函数传参中的传值和传址问题
函数传参中的传值和传址问题 函数传参的机制可以理解为传值pass-by-value和传址pass-by-reference的混合体但实际上更接近于传对象引用pass-by-object-reference。 不可变类型传值
对于不可变类型如整数、浮点数、字符串、元组等当你将它们作为参数传递给函数时似乎是在传值因为任何在函数内部对这些参数所做的修改都不会影响到函数外部的变量。
def modify_value(x):x 10 # 解释相当于将10的地址给到临时变量x替换了原来5的地址print(Inside function:, x, id(x)) # 解释所以打印的地址是10的地址a 5 # 解释将5的地址给到a
modify_value(a) # 解释相当于将a的地址给到modify_value函数中的临时变量x
print(Outside function:, a, id(a)) # 解释a的地址是5的地址# Inside function: 10 2450059455056
# Outside function: 5 2450059454896
# 地址发生变化因为小整数池的原因在这个例子中a 是一个整数对象当它被传递给 modify_value 函数时函数内部得到的是 a 的一个副本在内存中是一个新的整数对象 10而不是 a 本身。因此函数内部对 x 的修改不会影响到外部的 a。
然而这并不是说 Python 在传递这些值时进行了完整的拷贝。实际上Python 传递的是对不可变对象的引用但由于这些对象是不可变的所以你不能通过引用改变它们的内容。当你尝试改变它们时你实际上是在创建一个新的对象。
可变类型传址
对于可变类型如列表、字典、集合等当你将它们作为参数传递给函数时函数内部可以直接修改这些对象的内容这种行为看起来像是传址。
def modify_list(lst):lst.append(10) # 解释因为list列表是可变类型内容发生变化后地址不会变所以lst的地址还是传进来的my_list的地址2077876147584print(Inside function:, lst, id(lst)) # 解释所以打印的地址还是my_list的地址2077876147584但是内容变换了my_list [1, 2, 3]
modify_list(my_list) # 解释相当于将my_list的地址2077876147584给到modify_list函数中的临时变量lst
print(Outside function:, my_list, id(my_list)) # 解释因为在函数中将地址2077876147584的列表内容进行修改了但是my_list的地址没变还是指向2077876147584所以my_list的内容也跟着变化了# Inside function: [1, 2, 3, 10] 2077876147584
# Outside function: [1, 2, 3, 10] 2077876147584
# 地址没发生变化因为list列表为可变类型在这个例子中my_list 是一个列表对象当它被传递给 modify_list 函数时函数内部得到的是对同一个列表对象的引用。因此函数内部对 lst 的修改会影响到外部的 my_list。
传址和传值的对比解释重要 前情提要如过函数中给入的参数是函数中有的变量则在这个函数中变量会作为局部变量使用不会影响到外面同名的变量。 在Python中当我们提到“对象的地址”或“对象的内存地址”时我们实际上是在谈论一个更抽象的概念即对象的标识符。这个标识符是由Python解释器在内部生成的用于唯一地标识每个对象。虽然标识符在底层实现上可能与对象的实际内存地址有关但Python解释器并不直接暴露内存地址给开发者。标识符是一个更高级的抽象它允许Python在内存管理方面保持更大的灵活性。 list1 [a, b, c, [1,3,5]]
list2 list1[::-1]
list3 list1[1:-1]print(list1,id(list1)) # 输出: [a, b, c, [1, 3, 5]] 2464707002304
print(list2,id(list1)) # 输出: [[1, 3, 5], c, b, a] 2464707002304
print(list3,id(list1)) # 输出: [b, c] 2464707002304
print(-----------------------------------)def func1(l1, l2):l1 l2l2.append(10)func1(list2, list3)
print(-----------------------------------)
print(list1,id(list1)) # 输出: [a, b, c, [1, 3, 5]] 2464707002304
print(list2,id(list1)) # 输出: [[1, 3, 5], c, b, a] 2464707002304
print(list3,id(list1)) # 输出: [b, c, 10] 2464707002304# func1(list2, list3)实际上是将list2的‘身份标识符’给到了函数里的l1将list3的‘身份标识符’给到了函数里的l2
# 因为函数中存在l1这个赋值变量但是为什么l2不算是临时变量呢
# 是因为l1 l2这句通俗的说你要存放一个东西无论这个东西是什么你要先有一个位置
# l1就是这个位置l2就是这个东西而l2这个东西的来源就是靠调用func1()这个函数来分配的
# 同样l2.append(10)这一句只是对这个未知的l2进行的一步操作也没有创建一个叫l2的临时变量
# 综上函数中的l1是临时变量所以对l1的赋值操作不会影响到给予‘身份标识符’的list2
# 但是l2不是临时变量所以l2指代的就是list3所以l2的操作就会影响到给予‘身份标识符’的list3。# 如果函数改为
list1 [a, b, c, [1,3,5]]
list2 list1[::-1]
list3 list1[1:-1]print(list1,id(list1)) # 输出: [a, b, c, [1, 3, 5]] 2587051900864
print(list2,id(list1)) # 输出: [[1, 3, 5], c, b, a] 2587051900864
print(list3,id(list1)) # 输出: [b, c] 2587051900864
print(-----------------------------------)def func2(l1, l2):l1 l2l2 l2[::-1]func2(list2, list3)
print(-----------------------------------)
print(list1,id(list1)) # 输出: [a, b, c, [1, 3, 5]] 2587051900864
print(list2,id(list1)) # 输出: [[1, 3, 5], c, b, a] 2587051900864
print(list3,id(list1)) # 输出: [b, c] 2587051900864# 可以发现这次l2就没有影响到list3因为这次l2也变成了临时变量# 同理就算l1换成list1l2换成list2函数中的list1和list2也只是存在与函数中和全局的list1、list2不是同一个
list1 [a, b, c, [1,3,5]]
list2 list1[::-1]
list3 list1[1:-1]print(list1,id(list1)) # 输出: [a, b, c, [1, 3, 5]] 2221755744192
print(list2,id(list1)) # 输出: [[1, 3, 5], c, b, a] 2221755744192
print(list3,id(list1)) # 输出: [b, c] 2221755744192
print(-----------------------------------)def func2(list1, list2):list1 list2list2.pop()func2(list2, list3)
print(-----------------------------------)
print(list1,id(list1)) # 输出: [a, b, c, [1, 3, 5]] 2221755744192
print(list2,id(list1)) # 输出: [[1, 3, 5], c, b, a] 2221755744192
print(list3,id(list1)) # 输出: [b] 2221755744192# 结果就是函数中的list1临时变量既没有影响到全局同名的list1也没有影响到给予‘身份标识符’的list2
# 函数中的list2非临时变量只影响到给予‘身份标识符’的list3而没有影响到全局同名的list2总结 更准确地说Python 在函数传参时传递的是对对象的引用。对于不可变对象由于你不能改变它们的内容所以这种传递方式看起来像是传值。对于可变对象由于你可以改变它们的内容所以这种传递方式看起来像是传址。