Page 1 of 1

Why pass?

Posted: Sat Jul 31, 2010 4:56 am UTC
by rflrob
I'm teaching a python programming crash-course this summer, and previous years' lecture notes included the pass statement, which I'm considering not teaching (our time is limited). I've only ever used it for stubbing out functions, and the like, e.g.

Code: Select all

def fun(my_args):
    pass

but it seems to me that if you're going to write a function(/if statement/except clause, etc.) that does nothing, you might as well just comment out the lines, or return nothing, or just have an empty string, or any number of other ways to do it. I trust that Guido had a good reason for including it in the language, but that reason is not obvious to me (possibly because I am not Dutch). Any other ideas?

Re: Why pass?

Posted: Sat Jul 31, 2010 5:34 am UTC
by ++$_
It's to prevent indented blocks from being empty for parsing reasons, I think. It gives you something officially sanctioned to do there.

Also, it's easier to teach people to use pass if they want to do nothing than to tell them to put an empty string when they want to do nothing. The latter raises more questions than it answers, I think.

Re: Why pass?

Posted: Sat Jul 31, 2010 6:34 am UTC
by rflrob
++$_ wrote:It's to prevent indented blocks from being empty for parsing reasons, I think. It gives you something officially sanctioned to do there.

Also, it's easier to teach people to use pass if they want to do nothing than to tell them to put an empty string when they want to do nothing. The latter raises more questions than it answers, I think.


I get that it allows indented blocks to be empty, but what's still not making sense to me is why you'd want to have an empty block. If you want to do nothing, just don't have a block where you need to do anything, rather than making something where you need to do something, then passing

As far as the empty string business, a co-teacher of mine told the students "Oh, you can use triple quotes to comment out a bunch of code" (similar to /* */ in C), and that apparently didn't set off any red flags whatsoever with the students. I bit my tongue because I didn't really want to explain why what that was doing was both a) okay, and b) really, more than a little weird, and c) how to do it in emacs (btw... how do you do it in emacs?).

Re: Why pass?

Posted: Sat Jul 31, 2010 7:04 am UTC
by Xanthir
Empty blocks are good for a few reasons, mainly stubbing purposes. Sometimes it's good to go ahead and write down your intention to write a function or a class before you actually get around to writing the implementation.

It's also occasionally useful when you're subclassing something with slightly different expectations and want to disable a function you've inherited, or something demands to be passed a class but you don't actually need the functionality that it would use the class to provide.

Re: Why pass?

Posted: Sat Jul 31, 2010 9:57 am UTC
by Axidos
To add to the very good previous posts - pass exists for readability. It says "I have deliberately put nothing here because this portion of code is supposed to do absolutely nothing. If this block is empty that's absolutely deliberate and not a symptom of bad indentation or code someone should have removed."

It's a standard way of stubbing which doesn't leave you wondering why someone just wrote an empty string in that block.

Re: Why pass?

Posted: Sat Jul 31, 2010 10:37 am UTC
by PM 2Ring
The Python docs give this example:

Code: Select all

>>> while True:
...     pass  # Busy-wait for keyboard interrupt (Ctrl+C)
...

Another situation is in complicated if statements where one of the conditions appears like it might sometimes be true, but that deeper logical analysis shows that the condition will never be true. Of course, such statements should be explicitly commented.
Here's a simplified example:

Code: Select all

def move_jump_or_finish():
    if next_to_beeper():
        turn_off()
    elif front_is_clear():
        move()
    elif right_is_clear(): # always false
        pass
    else:
        jump_one_hurdle()

Some may argue that such code should be redesigned...

Personally, I mostly use pass during development, as a placeholder. Here's an example:

Code: Select all

elif event.button == 2:
    #print 'Single press of middle button'         
    pass

I don't remove such debugging print statements until I've finished working on a program, and occasionally leave them in programs that work adequately but that I intend to get back to at some stage.

OTOH, I also do things like

Code: Select all

#Debugging output level. 0=no debugging
verbosity = 0

#Debug output routine               
def printe(v, s):
      ''' Print to stderr '''
      if v <= verbosity:
          print >>sys.stderr, s

or

Code: Select all

#Debug output routine               
def print_stderr(s):
    ''' Print to stderr '''
    print >>sys.stderr, s

def print_null(s): pass                 

printe = debug and print_stderr or print_null   


I occasionally use the triple-quote technique for temporarily commenting-out code blocks during development; I find it handy and don't see why it'd be considered confusing, unless it appears at the head of the function.

Re: Why pass?

Posted: Sat Jul 31, 2010 12:18 pm UTC
by keeperofdakeys
This may be slightly trivial, but I have found it handy in try except blocks:

Code: Select all

try:
   //code
except SpecificError:
   pass

Re: Why pass?

Posted: Sat Jul 31, 2010 4:30 pm UTC
by Cleverbeans
keeperofdakeys wrote:This may be slightly trivial, but I have found it handy in try except blocks


This is where I find use for it as well.

Re: Why pass?

Posted: Sat Jul 31, 2010 6:59 pm UTC
by TNorthover
Unless I've missed it no-one has mentioned methods of polymorphic objects. Sometimes you want a function to exist and be callable without error, but not actually do anything.

Re: Why pass?

Posted: Sat Jul 31, 2010 7:38 pm UTC
by ++$_
rflrob wrote:c) how to do it in emacs (btw... how do you do it in emacs?).
I suggest pressing the quote key three times, then moving the cursor to the end of the region and pressing the quote key three times again.

(Did I miss something?)

Actually, I suggest not using this method to comment things out, because it will not work all the time. The code between the triple quotes ends up as an expression, so something like

Code: Select all

return a + """b""" c
is a syntax error, whereas

Code: Select all

return a + /* b */ c;
(in C) isn't.

EDIT: Semicolon!

Re: Why pass?

Posted: Sun Aug 01, 2010 4:03 am UTC
by troyp
PM 2Ring wrote:Another situation is in complicated if statements where one of the conditions appears like it might sometimes be true, but that deeper logical analysis shows that the condition will never be true. Of course, such statements should be explicitly commented.

If I test for a case that will should always be false, I always raise an exception rather than "pass"ing - that way it's pretty much self-commenting, plus it acts like an assertion.

I think it's good to have a pass keyword for readability. Sure, it's probably never necessary: you could use a dummy expression like "" wherever a pass command would go, but it's clearer to use an empty command to indicate your intent.
Apart from humans, it may also be clearer to tools. I've never used anything like PyLint, but I wouldn't be surprised if a code-checking tool warned about superfluous expressions appearing in your code.

Of course, you wouldn't need a special keyword to indicate an empty command if Python had optional semicolons like a sensible language.

Re: Why pass?

Posted: Sun Aug 01, 2010 1:02 pm UTC
by phlip

Code: Select all

class SomethingWentWrongError(EnvironmentError):
   pass

Re: Why pass?

Posted: Sun Aug 01, 2010 3:38 pm UTC
by TheChewanater

Code: Select all

class foo:
  def __iadd__ (self, from):
    if (from != '\x00'):
      chars += from
      return True
    else:
      return False

Code: Select all

class bar:
  def readNextChar ():
    if (moreChars) return nextChar
    else return '\x00'

Code: Select all

while foo += bar.readNextChar (): pass


I've never done that, but I guess it could conceivable be used sort of like this.

Re: Why pass?

Posted: Sun Aug 01, 2010 11:32 pm UTC
by rflrob
This:
TNorthover wrote:Unless I've missed it no-one has mentioned methods of polymorphic objects. Sometimes you want a function to exist and be callable without error, but not actually do anything.

and this:
phlip wrote:

Code: Select all

class SomethingWentWrongError(EnvironmentError):
   pass


were the good uses that I couldn't think of. Thanks!

As a side note:
TheChewanater wrote:

Code: Select all

while foo += bar.readNextChar (): pass


gives me a syntax error in Python 2.6.4. It's a perfectly good C idiom that just isn't legal in Python.

Re: Why pass?

Posted: Mon Aug 02, 2010 12:41 am UTC
by Xanthir
If I recall, that's because = and friends are statements rather than expressions, and if/while/etc require expressions in their clause.

I'm pretty sure they were set up that way specifically so you couldn't do that.

Re: Why pass?

Posted: Mon Aug 02, 2010 12:54 am UTC
by TheChewanater
I'm pretty sure you make make your class have a __iadd__ function with a return value. I could be wrong.

I guess you might have:

Code: Select all

while doSomethingIfPossibleOtherwiseReturnFalse (): pass

Re: Why pass?

Posted: Mon Aug 02, 2010 1:04 am UTC
by phlip
The assignment-is-not-an-expression thing, incidentally, makes regexes in Python a pain... this entirely reasonable Perl code:

Code: Select all

if ($line =~ /regex 1/)
{
  print "It matches regex 1!\n";
}
elsif ($line =~ /regex 2 - (.*)/)
{
  print "It matches regex 2! The rest is $1\n";
}
elsif ($line =~ /regex 3/)
{
  print "It matches regex 3!\n";
}
else
{
  print "It didn't match any of them!\n";
}
directly translates into this horrible Python code:

Code: Select all

match = re.search('regex 1', line)
if match:
  print "It matches regex 1!"
else:
  match = re.search('regex 2 - (.*)', line)
  if match:
    print "It matches regex 2! The rest is %s" % match.group(1)
  else:
    match = re.search('regex 3', line)
    if match:
      print "It matches regex 3!"
    else:
      print "It didn't match any of them!"
which gets very ugly when you've got a lot of formats to match. Luckily, this "match something from a list of patterns" deal is something I'm usually only doing when I'm hacking something together anyway, reading the output of some command or webpage or something, so using a hack to fix the problem isn't unreasonable:

Code: Select all

def store(v,x):
  v[0] = [x]
  return x

match = [None]
if store(match, re.search('regex 1', line)):
  print "It matches regex 1!"
elif store(match, re.search('regex 2 - (.*)', line)):
  print "It matches regex 2! The rest is %s" % match[0].group(1)
elif store(match, re.search('regex 3', line)):
  print "It matches regex 3!"
else:
  print "It didn't match any of them!"

I guess if this came up in a not-hack program, I'd do something more pythonish, like make a list of tuples of (regex,function), and loop through them to find the find the first one that matches, and call the appropriate function with the match object. Or something like that.

TheChewanater wrote:I'm pretty sure you make make your class have a __iadd__ function with a return value. I could be wrong.

Nope... it's a syntax error, regardless of the types of the values involved. Anyway, the return value from __iadd__ is assigned to the variable... "x += y" becomes "x = x.__iadd__(y)".

Re: Why pass?

Posted: Mon Aug 02, 2010 3:26 pm UTC
by Cosmologicon
PM 2Ring wrote:Another situation is in complicated if statements where one of the conditions appears like it might sometimes be true, but that deeper logical analysis shows that the condition will never be true. Of course, such statements should be explicitly commented.
Here's a simplified example:

Code: Select all

def move_jump_or_finish():
    if next_to_beeper():
        turn_off()
    elif front_is_clear():
        move()
    elif right_is_clear(): # always false
        pass
    else:
        jump_one_hurdle()

Some may argue that such code should be redesigned...

A condition needn't always be false for pass to make sense in a compound if statement. Sometimes that's the clearest way to write conditions:

Code: Select all

if asleep():
    pass
elif hungry():
    eat()
elif tired():
    go_to_sleep()
else:
    watch_tv()
In order to get the same logic without an empty statement, you'd either need to nest your ifs, or evaluate a condition more than once (or store it in a variable), both of which are arguably less clear than a pass statement.

Re: Why pass?

Posted: Mon Aug 02, 2010 11:58 pm UTC
by phlip
Cosmologicon wrote:

Code: Select all

if asleep():
    pass
elif hungry():
    eat()
elif tired():
    go_to_sleep()
else:
    watch_tv()
There's a serious bug in there... better would be:

Code: Select all

if asleep():
    pass
elif hungry():
    eat()
elif tired():
    go_to_sleep()
elif anything_good_on_tv(): # always false
    watch_tv()
else:
    play_computer_games()

Re: Why pass?

Posted: Tue Aug 03, 2010 1:54 am UTC
by Xeio
I'd also caution against going to sleep, as you'll never wake up again.... :P

Re: Why pass?

Posted: Tue Aug 03, 2010 10:46 am UTC
by Cosmologicon
Well obviously waking up is taken care of in the event handler for the alarm clock. :)

Re: Why pass?

Posted: Thu Aug 05, 2010 10:14 am UTC
by not baby Newt
phlip wrote:
TheChewanater wrote:I'm pretty sure you make make your class have a __iadd__ function with a return value. I could be wrong.

Nope... it's a syntax error, regardless of the types of the values involved. Anyway, the return value from __iadd__ is assigned to the variable... "x += y" becomes "x = x.__iadd__(y)".

You could implement a java-style add() method if you really like expressions that do things. Might be a tad unpythonic though?

Code: Select all

while foo.add( bar.readNextChar ()): pass

Re: Why pass?

Posted: Thu Aug 05, 2010 10:35 pm UTC
by troyp
Python has plenty of expressions with side-effects, eg. lst.reverse().
Although admittedly, they usually only return None or some success indicator.

Expressions like assignment in C/++ or stream operators in C++ where the operator does something with a value and then returns the same value with a result (allowing chaining)...yeah, those are probably unpythonic. Python has a side-effecting reverse() returning None and a pure reversed() method for lists, but combining the two in a method would be regarded as bad form.

I think the reason assignment isn't an expression in Python is specifically to control coding style. If you could use assignment as an expression, people would, and Guido wants to prevent that.
The one approved use-case (chained assignment, like a=b=0) is supported by special syntax (thus furthering the confusion of people coming from other languages ;-))

[edit: adjusted paragraph spacing for clarity]

Re: Why pass?

Posted: Fri Aug 06, 2010 12:05 am UTC
by RoadieRich
troyp wrote:Python has plenty of expressions with side-effects, eg. lst.reverse().
Although admittedly, they usually only return None or some success indicator. Expressions like assignment in C/++ or stream operators in C++ where the operator does something with a value and then returns the same value with a result (allowing chaining)...yeah, those are probably unpythonic. Python has a side-effecting reverse() returning None and a pure reversed() method for lists, but combining the two in a method would be regarded as bad form.
I think the reason assignment isn't an expression in Python is specifically to control coding style. If you could use assignment as an expression, people would, and Guido wants to prevent that.

The one approved use-case (chained assignment, like a=b=0) is supported by special syntax (thus furthering the confusion of people coming from other languages ;-))

I can't remember where I read it, but I'm pretty sure there's a PEP* which states functions, methods etc should either have a side effect, or a return value, but never both. Due to the way python functions work, if you don't explicitly return a value, it will return None, so list.reverse() complies. reversed(), on the other hand, doesn't have any side effects (the original list is unchanged), so it can return a value.

*At least, I think it's a PEP. It might be one of those generic "how to write good code" resources.

Re: Why pass?

Posted: Fri Aug 06, 2010 2:57 am UTC
by troyp
Exactly.
I tend to agree with them about this. It can be handy having side-effecting functions that modify an object and return the object as well, since it lets you chain a series of modifications together with dots (I've heard this style called "cascades", a term I couldn't recall earlier). However, it can become obfuscating if you start getting confused about which functions are mutating the original argument and which are returning a new object. I think in general it's better to write a series of mutations as a series of statements rather than embedding them in a complex expression. Especially in Python, which encourages a clean, uncluttered style of coding.

Anyhow, the main point I was making before is that, in general, expressions with side-effects are not at all unpythonic. Most side-effects in Python are achieved with functions or methods (which are expressions). Python3 even replaces the print statement with a print method, removing one of the few exceptions.
Statements in Python are usually either for definitions or control flow.

Re: Why pass?

Posted: Fri Aug 06, 2010 4:29 pm UTC
by not baby Newt
troyp wrote: I think in general it's better to write a series of mutations as a series of statements rather than embedding them in a complex expression. Especially in Python, which encourages a clean, uncluttered style of coding.

Anyhow, the main point I was making before is that, in general, expressions with side-effects are not at all unpythonic. Most side-effects in Python are achieved with functions or methods (which are expressions).

This is handy to know. Also slightly amusing (to me) that expressions with side effects are pythonic long as they are used as statements :D

Re: Why pass?

Posted: Fri Aug 06, 2010 5:25 pm UTC
by PM 2Ring
Speaking of side effects, I find this sort of thing handy from time to time:

Code: Select all

#! /usr/bin/env python
''' Create an accumulator function from a 2 arg function.
    Like a cross between map() & reduce().
'''
def acc(func, v0=0):
    def f(v, a=[v0]):
        a[0] = func(a[0], v)
        return a[0]
    return f

def main():
    f = acc(lambda u,v: u+v)
    print [f(i) for i in xrange(1,12)]

    f = acc(lambda u,v: u*v, 1)
    print [f(i) for i in xrange(1,12)]

if __name__ == '__main__':
    main()

Re: Why pass?

Posted: Sat Aug 07, 2010 1:27 pm UTC
by thoughtfully
Here's another one: multiple inheritance.

Code: Select all

class Foo(Mixin, Ancestor):
    pass

See, for example, the SocketServer documentation.

Re: Why pass?

Posted: Sun Aug 08, 2010 1:14 am UTC
by jagdragon
I find the use of pass most common while I'm working on larger programs - If one does not have a pass there, a syntax error occurs, which is really annoying if you just wanted to build up a skeleton of the program you're building.