[Tutor] Returning a list/dict as "read-only" from a method ?
Aztech Guy
aztech1200@yahoo.com
Wed Dec 25 14:37:01 2002
--0-1183573139-1040844479=:59877
Content-Type: text/plain; charset=us-ascii
Hi list,
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. Now, some time back, in the "call-by-reference in Python" thread, people (Danny was one, I think) had showed the 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 for the first case is given below, followed by the output of a run.
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
---------------------------------
Do you Yahoo!?
Yahoo! Mail Plus - Powerful. Affordable. Sign up now
--0-1183573139-1040844479=:59877
Content-Type: text/html; charset=us-ascii
<P><BR>Hi list,</P>
<P>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):</P>
<P>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. Now, some time back, in the "call-by-reference in Python" thread, people (Danny was one, I think) had showed the 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 ?</P>
<P>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.</P>
<P>Sample code for the first case is given below, followed by the output of a run.</P>
<P>class C1:<BR> def __init__(self, filename):<BR> # simulate reading data from the file and populating the dict.<BR> self.d1 = {}<BR> self.d1['key1'] = 'value1'<BR> self.d1['key2'] = 'value2'<BR> print 'in C1.__init__(), id(self.d1) = ', id(self.d1)</P>
<P> def get_dict(self):<BR> return self.d1</P>
<P>def main():<BR> c1 = C1('dummy')<BR> main_dict = c1.get_dict()<BR> print 'in main(), before modifying main_dict, id(main_dict) = ', id(main_dict)<BR> print 'and main_dict = ', main_dict<BR> main_dict['key2'] = 'a different value'<BR> main_dict = c1.get_dict()<BR> print 'in main(), after modifying main_dict, id(main_dict) = ', id(main_dict)<BR> print 'and main_dict = ', main_dict<BR> <BR>main()</P>
<P><BR>>>> in C1.__init__(), id(self.d1) = 24213904<BR>in main(), before modifying, id(main_dict) = 24213904<BR>and main_dict = {'key2': 'value2', 'key1': 'value1'}<BR>in main(), after modifying, id(main_dict) = 24213904<BR>and main_dict = {'key2': 'a different value', 'key1': 'value1'}<BR>>>> </P>
<P>Hope I've made the problem clear. If not, let me know.</P>
<P><BR>TIA <BR>Az</P>
<P> </P><p><br><hr size=1>Do you Yahoo!?<br>
<a href="http://rd.yahoo.com/mail/mailsig/*http://mailplus.yahoo.com">Yahoo! Mail Plus</a> - Powerful. Affordable. <a href="http://rd.yahoo.com/mail/mailsig/*http://mailplus.yahoo.com">Sign up now</a>
--0-1183573139-1040844479=:59877--