Does calling iter () on an instance of my class not create a “snapshot” of its current values?

So, I created a custom class in Python that supports iteration using the __iter__ method. My __iter__ method __iter__ structured as a generator object, using yield to give each of the values ​​in an instance of the class.

I find that if I say something like x = iter(my_instance) and then edit the data stored in my instance, if I subsequently create a list from x , I will find that this list contains the values ​​that my_class currently has, not the values ​​it had when iter() called.

So my question is this time doubled. First of all, is this what should happen? If so, why does it work?


Above is the main thing, but if you really want to go higher and further, read on. Now, the reason I am asking this question is because I needed to create this class as a task at the university. My professor provided a program that will do a bunch of tests in this class that I created to give me an idea of ​​whether I did it right the first time.

My program passes every check except the last one, which basically does what is described above. The problem is that he expects the list constructed from the previous call to iter(my_object) to reflect only the values ​​stored in my_object , while iter() was called on it.

My initial reaction after considering this was that my professor intended to get a result that looked like just calling list(my_object) , but I'm a student here, so most likely I just encoded my __iter__ method in this very weird way, which causes this behavior. Or has Python changed the way iter() functions recently?


I would prefer not to publish my code, as this is for the class, and this could technically be considered a hoax (I know this is stupid and useless, sorry). However, I can bind the specification, which is right here (in particular, part 1, class Bag ).

+5
source share
2 answers

Appointment seems to give you a strong hint of how you should do it

Make sure that the iterator produces these values ​​in the bag while the iterator starts execution; so mutating the bag during iteration will not affect what it produces.

Hint: write this method as a call to the local generator, passing a copy of the dictionary (see the lecture on Friday in the 4th week).

+1
source

As I think, @ Cyb3rFly3r tried to say that the iteration behavior on a volatile class makes it extremely disagreeable with how it works for container classes in the standard library, and therefore it will be somewhat controversial to choose a design that can only be done on these foundations in the real world .

It also contradicts, probably, one of the main reasons that the concept of iterators was introduced in Python, which was to create separate copies of the contents of container objects so that they could be repeated without need.

In any case, exactly what you need to do in your __iter__() method (and sounds like the one shown in Peter Gibson's Answer in the tip from article 11 of the related specification , suggests copying a dictionary that stores all the information in a Bag instance, be then a simple dict ionary, a defaultdict , or something else).

You can optimize things (minimizing the additional memory needed for copying and the simplicity of its internal repetition) by creating an internal list its contents, rather than making a copy of the entire likely more complex data structure. ** Tip **: Doing this will probably be very similar to what you need to do to implement the __repr__() method so that its results look like this:

Bag (['a', 'c', 'b', 'b', 'd', 'd', 'd'])

as shown in details of 3 specifications.

Since you decide not to publish any code, it will be much harder for you to help.

+2
source

Source: https://habr.com/ru/post/1247323/


All Articles