2

The 'while' doesn't 'break' when self.text is set to '' by the kill function.

Can someone help me make this work or suggest a better way? Need to run a string through 10+ functions quitting if string becomes '' Returning inside each function seems redundant.

class Class(object):
    def run(self, text):
        self.text = text

        while self.text:
            self.nothing1()
            self.kill()
            self.nothing2()
            return self.text # stop if all functions run

    def nothing1(self):
        print 'nothing1'
        self.text = self.text

    def kill(self):
        print 'kill'
        self.text = ''

    def nothing2(self):
        print 'nothing2'
        self.text = self.text

C = Class()
C.run('some string')

Clarification: Goal is to run a string through a many functions in order just once stopping if any one of the functions sets the string to "", i obviously misunderstand how 'while' work, it seems the cleanest way to me.

4
  • This code does actually break on the first iteration. Commented Mar 8, 2012 at 16:52
  • Correct, can someone clarify why it doesn't break at' kill'? Commented Mar 8, 2012 at 17:04
  • 3
    @mark Why should it stop after kill? There is not break statement. So it executes the rest of the functions bellow kill. But the next iteration of while doesn't go because the condition self.nect==True is not met. Commented Mar 8, 2012 at 17:08
  • +1 While loops may have been misunderstood, but the problem that needs solving is interesting and common. It is clear from the question, too. Commented Mar 8, 2012 at 17:45

4 Answers 4

4

Update 2: If your goal is to run a string through several functions, then your design is essentially all wrong.

Each function should NOT set a member, but instead accept a string, and return a string. Your loop should then test whether or not the value is good:

currstr = 'foo'
for f in (self.nothing1, self.kill, self.nothing2):
    tmpstr = f(currstr)
    if not tmpstr: break # or return, or raise exception
    currstr = tmpstr

Update: Apparently your problem is that you don't like how while loops work. While loops only break when execution hits the test - that is, once execution enters the body, absent a break or exception, it will continue to the end of the block, and only then will the test be re-evaluated.

Probably the cleanest way to do this is to wrap self.text with a property.

You then have three reasonable choices for the logic in your property function:

  1. You can create a system of handlers that are called when the property is changed, and do whatever you like there (including the logic of one the next two options);
  2. Include a specific test for an empty string, and raise an exception on that, and handle it outside of the loop; or
  3. Raise an exception on every single alteration, and handle it inside your loop.

You also have another option, which is to raise an exception in kill in much the same way as outlined above.


Your code works perfectly for me:

In [139]: cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:class Class(object):
:    def run(self, text):
:        self.text = text
:
:        while self.text:
:            self.nothing1()
:            self.kill()
:            self.nothing2()
:
:    def nothing1(self):
:        print 'nothing1'
:        self.text = self.text
:
:    def kill(self):
:        print 'kill'
:        self.text = ''
:
:    def nothing2(self):
:        print 'nothing2'
:        self.text = self.text
:
:C = Class()
:C.run('some string')
:--
nothing1
kill
nothing2
Sign up to request clarification or add additional context in comments.

4 Comments

As I got it, any function may set the text to ''. But I may be wrong.
Idea is to stop at kill and not to run nothing2
@mark I got it this way: any function may behave as kill by setting text=''. Otherwise it would be easier to add if condition with break after self.kill().
Thanks Marcin, i understand my mistake now.
2

You need to add a checking of text being '' after each function executing:

class Class(object):
    def run(self, text):
        self.text = text

        func_to_exec = [self.nothing1,self.kill,self.nothing2]
        while True:
            for func in func_to_exec:
                func()
                if not self.text:
                    break
            else:
                continue #executed only if no 'break' was met (starts the next iteration of `while` loop)
            break #get out of the 'while True' loop


    def nothing1(self):
        print 'nothing1'
        self.text = self.text

    def kill(self):
        print 'kill'
        self.text = ''

    def nothing2(self):
        print 'nothing2'
        self.text = self.text

Output:

>>> C.run('some string')
nothing1
kill

3 Comments

Thanks! Cleanest by far, however i don't think the 'while' is needed at all, it should break out of the 'for'
@mark Hm. As I got all those functions must be executed in an infinite loop untill one of them returns ''. No?
My bad, i forgot to included 'return self.text' at the bottom of the 'while'
1

While it may seem redundant, you can shorten the loop if you return the string in each function. It's a more functional approach to the problem, using lazy evaluation:

def run(self, text):
        self.text = text

        func_to_exec = [self.nothing1, self.kill, self.nothing2]
        all(func() for func in func_to_exec) # generator will evaluate func lazily

Nice and clear with a comment.

Comments

0

Write a decorator that raises StopIteration if the attribute becomes ''.

2 Comments

Does that mean a @decorator above each of the 10 functions? Not 100% on decorators but the idea is to not include redundant code in each function.
Either that, or wrap each of the calls in the decorator. Or you could do some __getattr__ magic, but you probably don't want to.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.