0

In datatstructures.py, there is a method values():

def values(self):
    """Iterate over all values."""
    for item in self:
        yield item[0]

self is an instance of the class; how can it be iterated over?

Pyderman
  • 14,809
  • 13
  • 61
  • 106
  • Possible duplicate of [Python iterating through object attributes](http://stackoverflow.com/questions/25150955/python-iterating-through-object-attributes) – sobolevn Jan 24 '16 at 17:58
  • Not a duplicate. My question is not *How to* but rather *How can* (as in: how can it be possible). – Pyderman Jan 24 '16 at 18:03

4 Answers4

2

The class which the given method belongs to extends ImmutableList which is iterable, thus the method can iterate on the class.

Siddharth Gupta
  • 1,573
  • 9
  • 24
1

Simple, it has to implement __iter__ method, e.g.

class Test:
    def __iter__(self):
        yield 1
        yield 2

>>> instance = Test()
>>> for val in instance:
...     print val
...
1
2
freakish
  • 54,167
  • 9
  • 132
  • 169
1

If the object in question is Iterable it can be iterated. This is how lists, dicts, and other sequences are designed.

Chad S.
  • 6,252
  • 15
  • 25
1

My question is not How to but rather How can (as in: how can it be possible)

self refers to the actual tangible object you deal with, classes are more like their interface (don't interpret this too strictly); if an instances' class defines a __iter__ (or __getitem__) method they can be iterated over in a for loop. PEP 234 deals with the semantics and implementation of iterators.

In your specific case the function is a generator which has nothing to do with the __iter__ method, it simply transforms the values function to a generator in order to support iteration of the form:

for i in instance.values(): # do stuff

If the object doesn't define an __iter__ it won't be able to be iterated over, as an example:

class myfoo:
    def func(self):
        for i in range(10): yield i

f = myfoo()

The instance f is now not iterable:

for i in f: print(i) # TypeError

On the other hand, we can use func in a for loop:

for i in f.func(): print(i, end=" ")
0 1 2 3 4 5 6 7 8 9

Changing func to __iter__ changes the picture, now the instance f is iterable:

class myfoo:
    def __iter__(self):
        for i in range(10): yield i

f = myfoo()

Iterating through f is done intuitively with:

for i in f: print(i, end=" ")
0 1 2 3 4 5 6 7 8 9

Asking why, as in, how can this be possible is like asking why can strings be multiplied with "s" * 4. This is the way things were implemented because it just made sense as a way of handling the common case of looping through the contents of a container. Don't overthink things, it isn't necessary.

Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253