don't train ai on me
don't train ai on me

Reputation: 1112

Pass an object to a function without it being modifiable in Python

Is there a simple/elegant way to pass an object to a function in a way that does not let it be modified from inside that function? As an example, for a passed array, it should not be possible to perform

array[2]=1 

and change the outer version of the array. That was an example, but I am looking for a solution that does not only work for arrays.

I have considered passing a copy, but this feels a little inelegant as it requires constant use of the copy library, and requires the constant computational effort of copying the object(s).

It is not an option to make the object somehow unmodifiable as a whole, because I do want it to be modified outside of the given function.

Upvotes: 1

Views: 1152

Answers (1)

Olivier Melançon
Olivier Melançon

Reputation: 22314

The short answer is no. There will always be a way to somehow access the object and update it.

Although, there are ways to discourage the mutation of the object. Here are a few.

Pass an immutable object

If some data should not be updated passed some point in the execution of your program, you should make it an immutable object.

my_data = []
populate_my_data(my_data) # this part of the code mutates 'my_data'

my_final_data = tuple(my_data)

Since my_final_data is a tuple, it cannot be mutated. Be aware that mutable objects contained in my_final_data can still be mutated.

Create a view on the object

Instead of passing the object itself, you could provide a view on the object. A view is some instance which provides ways to read your object, but not update it.

Here is how you could define a simple view on a list.

class ListView:
    def __init__(self, data):
        self._data = data

    def __getitem__(self, item):
        return self._data[item]

The above provides an interface for reading from the list with __getitem__, but none to update it.

my_list = [1, 2, 3]
my_list_view = ListView(my_list)

print(my_list_view[0]) # 1
my_list_view[0] = None # TypeError: 'ListView' object does not support item assignment

Once again, it is not completely impossible to mutate your data, one could access it through the field my_list_view._data. Although, this design makes it reasonnably clear that the list should not be mutated at that point.

Upvotes: 4

Related Questions