Two permutation iterators for classes in Python with and without a generator I am just testing out a couple of small classes for learning purposes. Here is my current working code:

class Permutation:
     '''An int list a permutation if starting at any index, one can reach every other index by
     repeated index accesses. The list [4, 0, 3, 1, 2] is a permutation: for example index 0
     stores a 4; index 4 stores a 2; index 2 stores a 3; index 3 stores a 1; index 1 stores a 0,
     bringing us back to that starting position after visiting every index.'''
     def __init__(self, p, start):
         self.p = p
         self.start = start

     def __iter__(self):
         class P_iter:
             def __init__(self, p, start):
                 self.p = p
                 self.start = start
                 self.curr = start
                 self.stahp = False

             def __next__(self):
                 if not self.stahp:
                     current = self.curr
                     self.curr = self.p[self.curr]
                     self.stahp = self.curr == self.start
                     return current
                  else:
                      raise StopIteration
         return P_iter(self.p, self.start)


class Permutation2:
     '''similar to the description above, but its __iter__ method should be implemented by a
     generator (not a P_iter nested class)'''
     def __init__(self,p,start):
         self.p = p
         self.start = start

     def __iter__(self):
         curr = self.start
         stahp = False
         while not stahp:
             yield curr
             curr = self.p[curr]
             stahp = curr == self.start
         else:
             raise StopIteration


I'm looking to clean the code a bit and maybe make it simpler. The code is fully working currently and generates the desired output.
Well Permutation has basically equivalent code to Permutation2, but is doing things the hard way.  Therefore, I'll just look at Permutation2, particularly __iter__().


 def __iter__(self):
     curr = self.start
     stahp = False
     while not stahp:
         yield curr
         curr = self.p[curr]
         stahp = curr == self.start
     else:
         raise StopIteration



You shouldn't need to explicitly raise StopIteration.  Iteration automatically stops when the flow of control reaches the end of the function.

I find the LoLcat spelling of "stop" amusing.  However, flag variables are generally a bad idea.  You would be better off writing if curr == self.start: break, for example.  However, I'd just choose to write it like this:

def __iter__(self):
    yield self.start
    curr = self.p[curr]
    while curr != self.start:
        yield curr
        curr = self.p[curr]


(Once again, the lack of a do-while loop in Python makes life difficult.)

Take care to indent your code very carefully in Python, as whitespace is significant.  Four spaces is a very strong norm, established in PEP 8.  You've used five spaces at the first level.