Differences between revisions 1 and 10 (spanning 9 versions)
Revision 1 as of 2005-09-03 01:32:31
Size: 281
Editor: NickCoghlan
Comment:
Revision 10 as of 2005-09-03 02:14:56
Size: 3152
Editor: NickCoghlan
Comment: Make comparison headings bold
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
This page discusses the benefits of replacing the current print statement with an equivalent builtin. The output function presented below does everything the print statement does without requiring an hacking of the grammar, and also makes a number of things significantly easier. This page discusses the benefits of replacing the current print statement with an equivalent builtin. The output function presented below does everything the print statement does without requiring any hacking of the grammar, and also makes a number of things significantly easier.

=== Benefits of using a function instead of a statement ===
 * Extended call syntax provides better interaction with sequences
 * Keyword argument `sep` allows separator to be changed easily and obviously
 * Keyword argument `term` allows line terminator to be changed easily and obviously
 * Keyword argument `stream` allows easy and obvious redirection
 * The builtin can be replaced for application wide customisation (e.g. per-thread logging)
 * Interacts well with PEP 309's partial function application

=== Sample implementation ===
This is a Python 2.4 compatible sample implementation, which is why it uses the name `output` rather than `print`. Try not to get too hung up on names at this stage :)

{{{#!python
def output(*args, **kwds):
    """Functional replacement for the print statement

    >>> output(1, 2, 3)
    1 2 3
    >>> output(1, 2, 3, sep='')
    123
    >>> output(1, 2, 3, sep=', ')
    1, 2, 3
    >>> output(1, 2, 3, term='Alternate line terminator')
    1 2 3Alternate line terminator
    >>> import sys
    >>> output(1, 2, 3, stream=sys.stderr)
    1 2 3
    >>> output(*range(10))
    0 1 2 3 4 5 6 7 8 9
    >>> output(*(x*x for x in range(10)))
    0 1 4 9 16 25 36 49 64 81
    """
    # Parse the keyword-only optional arguments
    defaults = {
        "sep": " ",
        "term": "\n",
        "stream": sys.stdout,
    }
    for name, default in defaults.items():
        item = None
        try:
            item = kwds[name]
        except KeyError:
            pass
        if item is None:
            kwds[name] = default
    sep, term, stream = kwds["sep"], kwds["term"], kwds["stream"]
    # Perform the print operation without building the whole string
    for arg in args[:1]:
        stream.write(str(arg))
    for arg in args[1:]:
        stream.write(sep)
        stream.write(str(arg))
    stream.write(term)
}}}

=== Code comparisons ===
These are some comparisons of current print statements with the equivalent code using the builtin (again, don't get too hung up on names here).

'''Standard printing:'''
{{{#!python
print 1, 2, 3
output(1, 2, 3)
}}}

'''Printing without any spaces:'''
{{{#!python
print "%d%d%d" % (1, 2, 3)
output(1, 2, 3, sep='')
}}}

'''Print as comma separated list:'''
{{{#!python
print "%d, %d%, d" % (1, 2, 3)
output(1, 2, 3, sep=', ')
}}}

'''Print without a trailing newline:'''
{{{#!python
print 1, 2, 3
output(1, 2, 3, term='')
}}}

'''Print to a different stream:'''
{{{#!python
print >> sys.stderr, 1, 2, 3
output(1, 2, 3, stream=sys.stderr)
}}}

'''Print a simple sequence:'''
{{{#!python
print " ".join(map(str, range(10)))
output(*range(10))
}}}

'''Print a generator expression:'''
{{{#!python
print " ".join(str(x*x) for x in range(10))
output(*(x*x for x in range(10)))
}}}

This page discusses the benefits of replacing the current print statement with an equivalent builtin. The output function presented below does everything the print statement does without requiring any hacking of the grammar, and also makes a number of things significantly easier.

Benefits of using a function instead of a statement

  • Extended call syntax provides better interaction with sequences
  • Keyword argument sep allows separator to be changed easily and obviously

  • Keyword argument term allows line terminator to be changed easily and obviously

  • Keyword argument stream allows easy and obvious redirection

  • The builtin can be replaced for application wide customisation (e.g. per-thread logging)
  • Interacts well with PEP 309's partial function application

Sample implementation

This is a Python 2.4 compatible sample implementation, which is why it uses the name output rather than print. Try not to get too hung up on names at this stage :)

   1 def output(*args, **kwds):
   2     """Functional replacement for the print statement
   3 
   4     >>> output(1, 2, 3)
   5     1 2 3
   6     >>> output(1, 2, 3, sep='')
   7     123
   8     >>> output(1, 2, 3, sep=', ')
   9     1, 2, 3
  10     >>> output(1, 2, 3, term='Alternate line terminator')
  11     1 2 3Alternate line terminator
  12     >>> import sys
  13     >>> output(1, 2, 3, stream=sys.stderr)
  14     1 2 3
  15     >>> output(*range(10))
  16     0 1 2 3 4 5 6 7 8 9
  17     >>> output(*(x*x for x in range(10)))
  18     0 1 4 9 16 25 36 49 64 81
  19     """
  20     # Parse the keyword-only optional arguments
  21     defaults = {
  22         "sep": " ",
  23         "term": "\n",
  24         "stream": sys.stdout,
  25     }
  26     for name, default in defaults.items():
  27         item = None
  28         try:
  29             item = kwds[name]
  30         except KeyError:
  31             pass
  32         if item is None:
  33             kwds[name] = default
  34     sep, term, stream = kwds["sep"], kwds["term"], kwds["stream"]
  35     # Perform the print operation without building the whole string
  36     for arg in args[:1]:
  37         stream.write(str(arg))
  38     for arg in args[1:]:
  39         stream.write(sep)
  40         stream.write(str(arg))
  41     stream.write(term)

Code comparisons

These are some comparisons of current print statements with the equivalent code using the builtin (again, don't get too hung up on names here).

Standard printing:

   1 print 1, 2, 3
   2 output(1, 2, 3)

Printing without any spaces:

   1 print "%d%d%d" % (1, 2, 3)
   2 output(1, 2, 3, sep='')

Print as comma separated list:

   1 print "%d, %d%, d" % (1, 2, 3)
   2 output(1, 2, 3, sep=', ')

Print without a trailing newline:

   1 print 1, 2, 3
   2 output(1, 2, 3, term='')

Print to a different stream:

   1 print >> sys.stderr, 1, 2, 3
   2 output(1, 2, 3, stream=sys.stderr)

Print a simple sequence:

   1 print " ".join(map(str, range(10)))
   2 output(*range(10))

Print a generator expression:

   1 print " ".join(str(x*x) for x in range(10))
   2 output(*(x*x for x in range(10)))

PrintAsFunction (last edited 2011-08-14 09:25:04 by eth595)

Unable to edit the page? See the FrontPage for instructions.