Detailed explanation of python function parameter transmission dict and list and set and other types of problems

  • 2021-10-16 02:23:23
  • OfStack

When passing a parameter, you pass a variable object, which is actually a pointer/reference to a memory address

This title is my conclusion, which I found in the process of doing the project. Anyone who has studied C knows that function parameters can be passed by values or pointers. The benefits of pointers are not repeated here.

First, go to the code to see the effect:


def trans(var):
  return var

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

Run results:

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

It can be seen that when source is changed, dist is also changed. The reason is that source is a mutable object, and when you pass a parameter, you pass its reference (pointer to C). dist and source both point to the same memory space. When running source [2] = 2, it is a change to the data in the memory space, so dist changes accordingly.

What's the effect? There should be many scenes, but my qualifications are still young, so I can't think of typical scenes, so take my own project as an example.

I defined a class in the project, which is used to read and write configurations, pre-store some json configurations, and the client can read the configurations. When the pre-stored configurations do not include the configurations read by the client, they are read from the device.

I need this class to instantiate multiple objects corresponding to multiple clients. But I want the pre-stored configuration to be public, so that for unfamiliar configurations, all client requests are not required to be read from the device.

1 This is what I wrote at first:


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:
      #  Pass device_url Gets the configuration from the device, if the value is assigned to the value
      dataset[key] = value
      return value
    
  def other_func(self):
    #  Other functions, following device_url Pertaining to 
    pass

Later, I needed multiple public configurations, even reaching more than 1,000 copies. Obviously, global variables can't be well satisfied. Because I want to share memory, I pass the mutable object and change the code to this:


class Config(object):
  
  def __init__(self, dataset, device_url):    #  Passing mutable objects 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:
      #  Pass device_url Gets the configuration from the device, if the value is assigned to the value
      self.dataset[key] = value    #  Variable object dataset Assignment, other instantiated dataset Property values also change 
      return value
    
  def other_func(self):
    #  Other functions, following device_url Pertaining to 
    pass

Lists, dictionaries and collections are not necessarily mutable objects

There is a pile of information on the Internet saying that lists, dictionaries and collections are mutable objects, which is not completely correct. {} [] set ((,)) constants are not mutable objects.

The above Config class cannot share configuration if it passes {} when instantiated.


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

The above operation result is

'{1: 1}'
'None'

But if so


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

The result of the run will become:

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

share_var is a mutable object, whereas {} is an immutable object, although the values of share_var and {} are identical.

To get a deeper understanding, you need to understand the namespace of python.

Things to pay attention to when passing parameters and variable object parameters

If you don't want to pass references/pointers to operate the corresponding memory space, be careful not to pass dictionaries, lists, collections, classes or instantiated objects of classes when passing parameters When passing variable object parameters, be careful not to pass the constant {} [] set ((,)). It is best to give a variable before passing the parameter, and pass this variable when passing the parameter.

Knowing the principle may not directly pass constants, but the following situations may occur:


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)) #  Here func1(mutable_object, False) Returns the {} Yes 1 Immutable objects 


Related articles: