文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

详解python函数传参传递dict/list/set等类型的问题

2024-04-02 19:55

关注

传参时传递可变对象,实际上传的是指向内存地址的指针/引用

这个标题是我的结论,也是我在做项目过程查到的。学过C的都知道,函数传参可以传值,也可以传指针。指针的好处此处不再赘述。

先上代码看看效果:


def trans(var):
  return var

source = {1: 1}
dist = trans(source)
source[2] = 2
print(source)
print(dist)

运行结果:

{1: 1, 2:2}
{1: 1, 2:2}

可以看到改变了source时,dist也跟着改变了。原因就是source是可变对象,传递参数时,传的是其引用(C的指针)。dist和source都指向了同一片内存空间。在运行source[2] = 2时,是对内存空间的数据的变更,所以dist也跟着变化。

有什么作用呢?场景应该很多,不过本人资历尚浅,想不到典型场景,就拿自己的项目举例。

项目中我定义了一个类,这个类用来读写配置,预存一些json配置,客户端可以读取配置,当预存的配置不包含客户端读取的配置时,就从设备读取。

我需要这个类实例化出多个对象,对应多个客户端。但我希望预存的配置可以是公共的,这样对于陌生配置,不用所有的客户端请求时,都需要从设备读取。

一开始我是这么写的:


global dataset
dataset = {}

class Config(object):
  def __init__(self, device_url):
    self.device_url = device_url
  
  def get_config(self, key):
    global dataset
    
    if key in dataset:
      return dataset.get(key)
    else:
      # 通过device_url从设备获取配置,假如赋值给了value
      dataset[key] = value
      return value
    
  def other_func(self):
    # 其他函数,跟device_url有关
    pass

而后来我需要多份公共配置,甚至要达到1000份以上,显然全局变量并不能很好满足。因为要共用内存,所以我传递可变对象,把代码改成了这样:


class Config(object):
  
  def __init__(self, dataset, device_url):    # 传递可变对象dataset
    self.dataset = dataset
    self.device_url = device_url
  
  def get_config(self, key):    
    if key in self.dataset:
      return self.dataset.get(key)
    else:
      # 通过device_url从设备获取配置,假如赋值给了value
      self.dataset[key] = value    # 可变对象dataset赋值,其他实例化的dataset属性值也会变化
      return value
    
  def other_func(self):
    # 其他函数,跟device_url有关
    pass

列表、字典、集合不一定是可变对象

网上有一堆资料说列表、字典、集合是可变对象,这句话不完全正确。{} [] set((, ))常量不是可变对象。

上述的Config类,如果实例化时传递{},就不能共享配置。


config1 = Config({})
config2 = Config({})
config1.dataset[1] = 1
print(repr(config1.dataset))
print(repr(config2,dataset))

上述运行结果是

'{1: 1}'
'None'

但如果是这样


share_var = {}
config1 = Config(share_var)
config2 = Config(share_var)
config1.dataset[1] = 1
print(repr(config1.dataset))
print(repr(config2,dataset))

运行结果就会变成:

'{1: 1}'
'{1: 1}'

share_var是可变对象,然而{}是不可变对象,虽然share_var和{}的值一样。

要往更深层次地理解,就需要理解python的命名空间了。

传参和传递可变对象参数需要注意的事情

懂了原理可能不至于直接传常量,但是有可能出现下面这种情况:


def func1(mutable_object, flag):
  if flag:
    return mutable_object
  else:
    return {}

def func2(mutable_object):
  # something to do with mutable_object
  pass

func2(func1(mutable_object, False)) # 此处func1(mutable_object, False)返回的是{},是一个不可变对象

到此这篇关于详解python函数传参传递dict/list/set等类型的问题的文章就介绍到这了,更多相关python函数传参传递内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网! 

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯