• 企业400电话
  • 网络优化推广
  • AI电话机器人
  • 呼叫中心
  • 全 部 栏 目

    网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    详解python函数传参传递dict/list/set等类型的问题
    POST TIME:2021-10-18 14:24

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

    这个标题是我的结论,也是我在做项目过程查到的。学过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函数传参传递内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

    您可能感兴趣的文章:
    • Python参数传递机制传值和传引用原理详解
    • Python 列表(List)操作方法详解
    • Python中list列表的一些进阶使用方法介绍
    • python开发中两个list之间传值示例
    上一篇:十分钟轻松掌握dataframe数据选择
    下一篇:python之Django自动化资产扫描的实现
  • 相关文章
  • 

    关于我们 | 付款方式 | 荣誉资质 | 业务提交 | 代理合作


    © 2016-2020 巨人网络通讯

    时间:9:00-21:00 (节假日不休)

    地址:江苏信息产业基地11号楼四层

    《增值电信业务经营许可证》 苏B2-20120278

    X

    截屏,微信识别二维码

    微信号:veteran88

    (点击微信号复制,添加好友)

     打开微信