Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python: unintentionally modifying parameters passed into a function

A few times I accidentally modified the input to a function. Since Python has no constant references, I'm wondering what coding techniques might help me avoid making this mistake too often?

Example:

class Table:
  def __init__(self, fields, raw_data):
    # fields is a dictionary with field names as keys, and their types as value 
    # sometimes, we want to delete some of the elements 
    for field_name, data_type in fields.items():
      if some_condition(field_name, raw_data):
        del fields[field_name]
    # ...


# in another module

# fields is already initialized here to some dictionary
table1 = Table(fields, raw_data1) # fields is corrupted by Table's __init__
table2 = Table(fields, raw_data2)

Of course the fix is to make a copy of the parameter before I change it:

  def __init__(self, fields, raw_data):
    fields = copy.copy(fields)
    # but copy.copy is safer and more generally applicable than .copy 
    # ...

But it's so easy to forget.

I'm half thinking to make a copy of each argument at the beginning of every function, unless the argument potentially refers to a large data set which may be expensive to copy or unless the argument is intended to be modified. That would nearly eliminate the problem, but it would result in a significant amount of useless code at the start of each function. In addition, it would essentially override Python's approach of passing parameters by reference, which presumably was done for a reason.

like image 249
max Avatar asked Sep 11 '11 17:09

max


People also ask

How to pass parameters to a function in Python?

Effective Ways to Pass Parameters to Python Functions 1. Positional argument. The order in which arguments are passed matters. Function when called matches the order in which... 2. Keyword argument. The argument passed is name-value pair. The order in which arguments are passed doesn't really... 3. ...

How are arguments passed from one function to another in Python?

Arguments are always passed to functions by reference in Python. The caller and the function code blocks share the same object or variable.

What is the difference between parameter names and arguments in Python?

The parameter names are used in the code within the function definition. When you call the function, you pass arguments within the parentheses, one for each parameter. An argument is a value you pass to the function.

How to pass unknown number of arguments to a python function?

Python lets us use its functionality to pass unknown number of arguments to a function. It basically create an empty tuple when see an argument as unknown number of parameter. It keeps on adding the parameters then based on the values passed to it.


1 Answers

First general rule: don't modify containers: create new ones.

So don't modify your incoming dictionary, create a new dictionary with a subset of the keys.

self.fields = dict( key, value for key, value in fields.items()
                     if accept_key(key, data) )

Such methods are typically slightly more efficient then going through and deleting the bad elements anyways. More generally, its often easier to avoid modifying objects and instead create new ones.

Second general rule: don't modify containers after passing them off.

You can't generally assume that containers to which you have passed data have made their own copies. As result, don't try to modify the containers you've given them. Any modifications should be done before handing off the data. Once you've passed the container to somebody else you are no longer the sole master of it.

Third general rule: don't modify containers you didn't create.

If you get passed some sort of container, you do not know who else might be using the container. So don't modify it. Either use the unmodified version or invoke rule1, creating a new container with the desired changes.

Fourth general rule: (stolen from Ethan Furman)

Some functions are supposed to modify the list. That is their job. If this is the case make that apparent in the function name (such as the list methods append and extend).

Putting it all together:

A piece of code should only modify a container when it is the only piece of code with access to that container.

like image 88
Winston Ewert Avatar answered Oct 25 '22 15:10

Winston Ewert