<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Iteration, Iterable, Iterator and Generator
The object that is returned from range() function can be converted to a list, but actually, it just returns value one by one. range(1000000) does not preserve memory space for 1000000 integers. (range() function of Python2 returns List)
Any time you use a loop, explicit or implicit, to go over a group of items, that is iteration.
Iterable is an object that you can get an Iterator from. In other word, Iterable is an object that has an __iter__ method which returns Iterator. iter() function calls __iter__ method.  
Iterator is an object with a __next__ method. next() function calls __next__ method.  
The object such as String or List is an Iterable, but not Iterator, which can not return element to next().
Step2:  Creating iterable object
Iterable object can be defined using class.
Step3:  Generator
Generators are a simple and powerful tool for creating iterators. They are written like regular functions but use the yield statement whenever they want to return data. Each time next() is called on it, the generator resumes where it left off (it remembers all the data values and which statement was last executed).
<ASSISTANT_TASK:>
Python Code:
# iterable objecct retuns iterator to iter() function
s = 'abc'
itr = iter(s)
print(next(itr))
print(next(itr))
print(next(itr))
## __iter__() function and __next__() function can be called directly as well
x = s.__iter__()
print(x.__next__())
print(next(x))
# StopIteration signal is raised after all items are retrieved
print(next(itr))
# STRING is a iterable, but not iterator. It does not support __next__ method
next(s)
Explanation: Iteration, Iterable, Iterator and Generator
The object that is returned from range() function can be converted to a list, but actually, it just returns value one by one. range(1000000) does not preserve memory space for 1000000 integers. (range() function of Python2 returns List)
Any time you use a loop, explicit or implicit, to go over a group of items, that is iteration.
Iterable is an object that you can get an Iterator from. In other word, Iterable is an object that has an __iter__ method which returns Iterator. iter() function calls __iter__ method.  
Iterator is an object with a __next__ method. next() function calls __next__ method.  
The object such as String or List is an Iterable, but not Iterator, which can not return element to next().
End of explanation
class Reverse:
    Iterator for looping over a sequence backwards.
    def __init__(self, data):
        self.data = data
        self.index = len(data)
    def __iter__(self):
        return self
    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]
rev = Reverse('UCSY')
for c in rev:
    print(c)
    
print('---')
    
rev = Reverse([100, 200, 300])
for c in rev:
    print(c)
Explanation: Creating iterable object
Iterable object can be defined using class.
End of explanation
def rev_gen(data):
#    for index in range(len(data)-1, -1, -1):
#        yield data[index]
    for elem in data[::-1]:
        yield elem
rev = rev_gen('ucsy')
for c in rev:
    print(c)
type(rev)
Explanation: Generator
Generators are a simple and powerful tool for creating iterators. They are written like regular functions but use the yield statement whenever they want to return data. Each time next() is called on it, the generator resumes where it left off (it remembers all the data values and which statement was last executed).
End of explanation
<END_TASK>