Returning a list/dict as "read-only" from a method ?

Az Tech aztech1200 at yahoo.com
Thu Dec 26 08:31:07 EST 2002


Hello group,

Platform: ActivePython 2.2.1 on Windows 98 - but nothing OS-specific 
in the code.

Sample code is given at the end of the post. The problem description 
is just below.

I've looked at the Python docs but couldn't get a solution. Please
 suggest some approach to a solution.

TIA
Aztech.


This question is about how to return a list/dictionary from a method
(of a class) in such a way that it stays "read-only" to the caller -
or any other technique that is equivalent in terms of effect. Read on
for the gory details (slightly long post, sorry):

I have a class - call it C1, whose purpose in life is to read data
from a binary file, and maintain some of the data read, as member
variables of the class. It should provide some methods that allow
clients to get the values of that data. Some of the data is structured
in nature (i.e. some of the individual data elements logically belong
together, as in a C struct), so I was planning to return such data  -
from one method, as a list - and from another method, as a dictionary.
I made use of the id() function to identify when two different
variables actually refer to the same piece of memory. As a test, I
wrote a dummy class and 2 methods as above (one of which returned a
list and the other a dictionary); when I printed id(<my_dict_or_list>)
from within the method, and also from the caller of the method
(invoked via a created object of that class, of course), I found that
id() returns the same value in both places. I think this means that
any caller of my object's method, can modify my member variable (list
or dictionary) that I am returning via the method. I don't want to let
this happen, obviously. (If I allowed it, then, each time the method
was called, instead of simply returning the list/dictionary member
variable originally created, I would have to re-read that data from
the file, and return the re-read data instead of my original copy in
my member variable. (I would not be able to simply return my original
copy of the data, since the first caller (as also any subsequent
callers) would have a reference to the very same member variable (as
shown by the calls to id(), and hence could potentially have modified
it, thereby changing my member variable from its original value read
from the file.) This re-reading would be highly inefficient due to
repeated file I/O to read the same data multiple times - as opposed to
reading it once from the file, saving it in a member variable, and
then simply returning that variable whenever the method was called
from the 2nd time onwards.) So what I did next was to write a fragment
of code inside each method (just after the code to read data from the
file), to make a copy of the list/dictionary, and return that copy
instead. Now, even if my caller modifies my return value, it doesn't
matter, as they are only modifying a copy, and my original is intact.
I do this create-and-return-a-copy each time the method is called.
What occurred to me next, is that to perform the memory-to-memory copy
- in the method - each time the method is called - is still
inefficient - particularly if the list/dictionary's size is more than
a few (or few hundred) bytes (though of course, its much faster than
re-reading the data each time from the file). Is there any way that I
can avoid the need to re-read data from the file, as well as the need
to do a memory-to-memory copy, each time the method is called, and
yet, prevent a caller from modifying my class's list/dictionary ?

I planned to do the memory-to-memory copy of the list/dictionary in a
hand-coded fashion - by iterating through the list/dictionary's items.
I am aware that there may be better ways to do this - like 'deepcopy'
or some such, but haven't looked into them yet. Anyway, I don't think
any other way of copying would help solve my problem, since what I am
aiming at is to avoid the copy in the first place - except for a
one-time copy, if needed.

Sample code:

class C1:
    def __init__(self, filename):
        # simulate reading data from the file and populating the dict.
        self.d1 = {}
        self.d1['key1'] = 'value1'
        self.d1['key2'] = 'value2'
        print 'in C1.__init__(), id(self.d1) = ', id(self.d1)

    def get_dict(self):
        return self.d1

def main():
    c1 = C1('dummy')
    main_dict = c1.get_dict()
    print 'in main(), before modifying main_dict, id(main_dict) = ',
id(main_dict)
    print 'and main_dict = ', main_dict
    main_dict['key2'] = 'a different value'
    main_dict = c1.get_dict()
    print 'in main(), after modifying main_dict, id(main_dict) = ',
id(main_dict)
    print 'and main_dict = ', main_dict
   
main()


>>> in C1.__init__(), id(self.d1) =  24213904
in main(), before modifying, id(main_dict) =  24213904
and main_dict =  {'key2': 'value2', 'key1': 'value1'}
in main(), after modifying, id(main_dict) =  24213904
and main_dict =  {'key2': 'a different value', 'key1': 'value1'}
>>>     

Hope I've made the problem clear. If not, let me know.


TIA 
Az



More information about the Python-list mailing list