Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Post History

71%
+3 −0
Q&A How can I output / display multiple values, with controlled spacing, without building a string?

Using the write method The write method of a file offers a much more limited interface. It only accepts one argument - a string, for a file opened in text mode - and outputs just what it's given. ...

posted 9mo ago by Karl Knechtel‭  ·  edited 9mo ago by Karl Knechtel‭

Answer
#2: Post edited by user avatar Karl Knechtel‭ · 2023-08-06T05:40:57Z (9 months ago)
  • ## Using the `write` method
  • The `write` method of a file offers a much more limited interface. It only accepts one argument - a string, for a file opened in text mode - and outputs just what it's given. Any additional desired spacing must be specified explicitly.
  • Sometimes, this makes it practical to combine approaches: rather than trying to format an entire string to write to the file, format each piece as it is written - for example, to add whitespace or other decoration.
  • This could look like:
  • ```python
  • # We have a `cookbook` full of recipes (some data structure),
  • # and want to write formatted info to the already open `menu` file.
  • for recipe in cookbook:
  • menu.write(f'{recipe.title} ${recipe.total_cost * 4:.2f}\n')
  • # Assume the result we get back from ChatGPT ends with a newline.
  • menu.write(chatgpt_rewrite_for_marketing(recipe.description))
  • # Comply with regulatory requirements.
  • menu.write(f'({recipe.calories} calories)\n')
  • ```
  • ## `print` and newlines
  • Any approach that works with the `write` method of a file can also be used with the `print` function in Python 3. However, as noted in the question, `print` will automatically put a newline after its output by default. To avoid this, change the default using the `end` keyword parameter:
  • ```python
  • >>> print('spam') # the next prompt shows up on the next line.
  • spam
  • >>> print('spam', end='') # the next prompt shows up immediately after.
  • spam>>>
  • ```
  • The argument provided for `end` can be any string. (It can also be `None`, which just gives the default behaviour - i.e., it's the same as using `'\n'`.)
  • ## `print` is flexible
  • The `print` function accepts *any number* of positional arguments with values to display, one after the other; these values can be of any type - the function will convert them to string as needed (using `str` logic).
  • ```
  • >>> print(1, 2, {'buckle': 'my'}, 'shoe')
  • 1 2 {'buckle': 'my'} shoe
  • ```
  • (Notice that the key and value in the dictionary are output with quotes - because they are actually part of the string created by converting the dictionary to string.)
  • `print` also accepts certain specific *keyword-only* arguments (they have to be specified by keyword, so that it can know that they aren't part of the output). As noted in the previous section, the `end` keyword-only argument controls what is output after the last item. Similarly, the `sep` keyword-only argument controls output *between* each item. As the previous example demonstrates, this defaults to a single space. Using `sep=''` squashes the results together:
  • ```
  • >>> print(1, 2, {'buckle': 'my'}, 'shoe', sep='')
  • 12{'buckle': 'my'}shoe
  • ```
  • (but there is still a space inside the dictionary output, because again, it is *part of the string* created from the dictionary.)
  • Keep in mind that nothing prevents using string formatting techniques on individual arguments to `print`. Techniques can be mixed and matched freely.
  • There are two more keyword-only arguments supported by `print`, which require separate discussion.
  • ## Gotcha: terminal line buffering
  • When a Python program `print`s data in a terminal window, Python itself is *not actually responsible for making the text display* (and neither is the script). That's handled by *the operating system itself*, indirectly via a) the "shell" program that interprets the command line and b) the terminal program that creates and maintains the window.
  • For efficiency reasons, when this text is communicated, it typically goes into a buffer and will only be displayed when a complete line of output (i.e., ending with a newline) is available, or when it gets some other explicit signal.
  • <section class='notice is-warning'>
  • **That means that code like the following *will normally not work as intended*:**
  • ```
  • import time
  • chant = ['spam'] * 5 + ['lovely'] + ['spam'] * 2
  • for word in chant:
  • print(word, end=' ')
  • time.sleep(0.4)
  • ```
  • </section>
  • Using `end` this way is useful for making a line appear incrementally, but in this example, the text will probably not show up piece by piece - instead, there is a long pause and then it all appears together. This is because of the line buffering.
  • <section class='notice is-success'>
  • **To avoid the problem, use the (boolean) `flush` keyword parameter:**
  • ```
  • import time
  • chant = ['spam'] * 5 + ['lovely'] + ['spam'] * 2
  • for word in chant:
  • print(word, end=' ', flush=True)
  • time.sleep(0.4)
  • ```
  • </section>
  • This tells the operating system to use the text in the buffer after the `print` call is done, even if it doesn't end with a newline.
  • ## Displaying to the terminal is actually just like writing a file
  • When the script outputs text with `print`, normally it does so by sending data to the so-called *standard output* - where the shell program will detect it and allow the terminal to display it. From the operating system's perspective, the standard output *is a file*, which Python also represents using the built-in file type. The `sys` standard library allows us to see this:
  • ```
  • >>> import sys
  • >>> sys.stdout
  • <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
  • ```
  • The last keyword parameter for `print` is the `file` parameter. This defaults to `sys.stdout`, as one would expect, but can be substituted with any object that has a `write` method (or with `None`, to get the default behaviour) In particular, it can be used to produce formatted output for files:
  • ```python
  • # Re-working the first example.
  • for recipe in cookbook:
  • print(recipe.title, f'${recipe.total_cost * 4:.2f}', file=menu)
  • menu.write(chatgpt_rewrite_for_marketing(recipe.description))
  • print(f'({recipe.calories} calories)', file=menu)
  • ```
  • This version takes advantage of the ability to specify multiple outputs at once, and the default `sep` and `end` values.
  • <details>
  • <summary>Advanced usage: working with sys.stdout</summary>
  • Of course, it's also possible to call the `.write` method of `sys.stdout` directly, just as one would with any other file.
  • It's even possible to *replace* sys.stdout with another object, which will affect future `print` calls. When no `file` argument is provided (or if it's `None`), `print` will look up the *current value* of `sys.stdout` rather than always using the *actual* standard output.
  • When doing this, it's best to use another variable to "remember" the previous file object, so that it can be restored later:
  • ```
  • >>> old_stdout = sys.stdout
  • >>> class devnull: # define a fake "file" type that ignores everything.
  • ... def write(self, text):
  • ... pass
  • ...
  • >>> sys.stdout = devnull() # make and use a fake
  • >>> print('This will not be seen')
  • >>> sys.stdout = old_stdout # good thing we remembered!
  • >>> print('This will be seen')
  • This will be seen
  • ```
  • </details>
  • ## Using the `write` method
  • The `write` method of a file offers a much more limited interface. It only accepts one argument - a string, for a file opened in text mode - and outputs just what it's given. Any additional desired spacing must be specified explicitly.
  • Sometimes, this makes it practical to combine approaches: rather than trying to format an entire string to write to the file, format each piece as it is written - for example, to add whitespace or other decoration.
  • This could look like:
  • ```python
  • # We have a `cookbook` full of recipes (some data structure),
  • # and want to write formatted info to the already open `menu` file.
  • for recipe in cookbook:
  • menu.write(f'{recipe.title} ${recipe.total_cost * 4:.2f}\n')
  • # Assume the result we get back from ChatGPT ends with a newline.
  • menu.write(chatgpt_rewrite_for_marketing(recipe.description))
  • # Comply with regulatory requirements.
  • menu.write(f'({recipe.calories} calories)\n')
  • ```
  • ## `print` and newlines
  • Any approach that works with the `write` method of a file can also be used with the `print` function in Python 3. However, as noted in the question, `print` will automatically put a newline after its output by default. To avoid this, change the default using the `end` keyword parameter:
  • ```python
  • >>> print('spam') # the next prompt shows up on the next line.
  • spam
  • >>> print('spam', end='') # the next prompt shows up immediately after.
  • spam>>>
  • ```
  • The argument provided for `end` can be any string. (It can also be `None`, which just gives the default behaviour - i.e., it's the same as using `'\n'`.)
  • ## `print` is flexible
  • The `print` function accepts *any number* of positional arguments with values to display, one after the other; these values can be of any type - the function will convert them to string as needed (using `str` logic).
  • ```
  • >>> print(1, 2, {'buckle': 'my'}, 'shoe')
  • 1 2 {'buckle': 'my'} shoe
  • ```
  • (Notice that the key and value in the dictionary are output with quotes - because they are actually part of the string created by converting the dictionary to string.)
  • `print` also accepts certain specific *keyword-only* arguments (they have to be specified by keyword, so that it can know that they aren't part of the output). As noted in the previous section, the `end` keyword-only argument controls what is output after the last item. Similarly, the `sep` keyword-only argument controls output *between* each item. As the previous example demonstrates, this defaults to a single space. Using `sep=''` squashes the results together:
  • ```
  • >>> print(1, 2, {'buckle': 'my'}, 'shoe', sep='')
  • 12{'buckle': 'my'}shoe
  • ```
  • (but there is still a space inside the dictionary output, because again, it is *part of the string* created from the dictionary.)
  • Keep in mind that nothing prevents using string formatting techniques on individual arguments to `print`. Techniques can be mixed and matched freely.
  • There are two more keyword-only arguments supported by `print`, which require separate discussion.
  • ## Gotcha: terminal line buffering
  • When a Python program `print`s data in a terminal window, Python itself is *not actually responsible for making the text display* (and neither is the script). That's handled by *the operating system itself*, indirectly via a) the "shell" program that interprets the command line and b) the terminal program that creates and maintains the window.
  • For efficiency reasons, when this text is communicated, it typically goes into a buffer and will only be displayed when a complete line of output (i.e., ending with a newline) is available, or when it gets some other explicit signal.
  • <section class='notice is-warning'>
  • **That means that code like the following *will normally not work as intended*:**
  • ```
  • import time
  • chant = ['spam'] * 5 + ['lovely'] + ['spam'] * 2
  • for word in chant:
  • print(word, end=' ')
  • time.sleep(0.4)
  • ```
  • </section>
  • Using `end` this way is useful for making a line appear incrementally, but in this example, the text will probably not show up piece by piece - instead, there is a long pause and then it all appears together. This is because of the line buffering.
  • <section class='notice is-success'>
  • **To avoid the problem, use the (boolean) `flush` keyword parameter:**
  • ```
  • import time
  • chant = ['spam'] * 5 + ['lovely'] + ['spam'] * 2
  • for word in chant:
  • print(word, end=' ', flush=True)
  • time.sleep(0.4)
  • ```
  • </section>
  • This tells the operating system to use the text in the buffer after the `print` call is done, even if it doesn't end with a newline.
  • ## Displaying in the terminal is just like writing a file
  • When the script outputs text with `print`, normally it does so by sending data to the so-called *standard output* - where the shell program will detect it and allow the terminal to display it. From the operating system's perspective, the standard output *is a file*, which Python also represents using the built-in file type. The `sys` standard library allows us to see this:
  • ```
  • >>> import sys
  • >>> sys.stdout
  • <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
  • ```
  • The last keyword parameter for `print` is the `file` parameter. This defaults to `sys.stdout`, as one would expect, but can be substituted with any object that has a `write` method (or with `None`, to get the default behaviour) In particular, it can be used to produce formatted output for files:
  • ```python
  • # Re-working the first example.
  • for recipe in cookbook:
  • print(recipe.title, f'${recipe.total_cost * 4:.2f}', file=menu)
  • menu.write(chatgpt_rewrite_for_marketing(recipe.description))
  • print(f'({recipe.calories} calories)', file=menu)
  • ```
  • This version takes advantage of the ability to specify multiple outputs at once, and the default `sep` and `end` values.
  • <details>
  • <summary>Advanced usage: working with sys.stdout</summary>
  • Of course, it's also possible to call the `.write` method of `sys.stdout` directly, just as one would with any other file.
  • It's even possible to *replace* sys.stdout with another object, which will affect future `print` calls. When no `file` argument is provided (or if it's `None`), `print` will look up the *current value* of `sys.stdout` rather than always using the *actual* standard output.
  • When doing this, it's best to use another variable to "remember" the previous file object, so that it can be restored later:
  • ```
  • >>> old_stdout = sys.stdout
  • >>> class devnull: # define a fake "file" type that ignores everything.
  • ... def write(self, text):
  • ... pass
  • ...
  • >>> sys.stdout = devnull() # make and use a fake
  • >>> print('This will not be seen')
  • >>> sys.stdout = old_stdout # good thing we remembered!
  • >>> print('This will be seen')
  • This will be seen
  • ```
  • </details>
#1: Initial revision by user avatar Karl Knechtel‭ · 2023-08-06T05:37:45Z (9 months ago)
## Using the `write` method

The `write` method of a file offers a much more limited interface. It only accepts one argument - a string, for a file opened in text mode - and outputs just what it's given. Any additional desired spacing must be specified explicitly.

Sometimes, this makes it practical to combine approaches: rather than trying to format an entire string to write to the file, format each piece as it is written - for example, to add whitespace or other decoration.

This could look like:
```python
# We have a `cookbook` full of recipes (some data structure),
# and want to write formatted info to the already open `menu` file.
for recipe in cookbook:
    menu.write(f'{recipe.title} ${recipe.total_cost * 4:.2f}\n')
    # Assume the result we get back from ChatGPT ends with a newline.
    menu.write(chatgpt_rewrite_for_marketing(recipe.description))
    # Comply with regulatory requirements.
    menu.write(f'({recipe.calories} calories)\n')
```

## `print` and newlines

Any approach that works with the `write` method of a file can also be used with the `print` function in Python 3. However, as noted in the question, `print` will automatically put a newline after its output by default. To avoid this, change the default using the `end` keyword parameter:
```python
>>> print('spam') # the next prompt shows up on the next line.
spam
>>> print('spam', end='') # the next prompt shows up immediately after.
spam>>> 
```
The argument provided for `end` can be any string. (It can also be `None`, which just gives the default behaviour - i.e., it's the same as using `'\n'`.)

## `print` is flexible

The `print` function accepts *any number* of positional arguments with values to display, one after the other; these values can be of any type - the function will convert them to string as needed (using `str` logic).
```
>>> print(1, 2, {'buckle': 'my'}, 'shoe')
1 2 {'buckle': 'my'} shoe
```
(Notice that the key and value in the dictionary are output with quotes - because they are actually part of the string created by converting the dictionary to string.)

`print` also accepts certain specific *keyword-only* arguments (they have to be specified by keyword, so that it can know that they aren't part of the output). As noted in the previous section, the `end` keyword-only argument controls what is output after the last item. Similarly, the `sep` keyword-only argument controls output *between* each item. As the previous example demonstrates, this defaults to a single space. Using `sep=''` squashes the results together:

```
>>> print(1, 2, {'buckle': 'my'}, 'shoe', sep='')
12{'buckle': 'my'}shoe
```
(but there is still a space inside the dictionary output, because again, it is *part of the string* created from the dictionary.)

Keep in mind that nothing prevents using string formatting techniques on individual arguments to `print`. Techniques can be mixed and matched freely.

There are two more keyword-only arguments supported by `print`, which require separate discussion.

## Gotcha: terminal line buffering

When a Python program `print`s data in a terminal window, Python itself is *not actually responsible for making the text display* (and neither is the script). That's handled by *the operating system itself*, indirectly via a) the "shell" program that interprets the command line and b) the terminal program that creates and maintains the window.

For efficiency reasons, when this text is communicated, it typically goes into a buffer and will only be displayed when a complete line of output (i.e., ending with a newline) is available, or when it gets some other explicit signal. 

<section class='notice is-warning'>

**That means that code like the following *will normally not work as intended*:**
```
import time
chant = ['spam'] * 5 + ['lovely'] + ['spam'] * 2
for word in chant:
    print(word, end=' ')
    time.sleep(0.4)
```
</section>

Using `end` this way is useful for making a line appear incrementally, but in this example, the text will probably not show up piece by piece - instead, there is a long pause and then it all appears together. This is because of the line buffering.

<section class='notice is-success'>

**To avoid the problem, use the (boolean) `flush` keyword parameter:**
```
import time
chant = ['spam'] * 5 + ['lovely'] + ['spam'] * 2
for word in chant:
    print(word, end=' ', flush=True)
    time.sleep(0.4)
```
</section>

This tells the operating system to use the text in the buffer after the `print` call is done, even if it doesn't end with a newline. 

## Displaying to the terminal is actually just like writing a file

When the script outputs text with `print`, normally it does so by sending data to the so-called *standard output* - where the shell program will detect it and allow the terminal to display it. From the operating system's perspective, the standard output *is a file*, which Python also represents using the built-in file type. The `sys` standard library allows us to see this:
```
>>> import sys
>>> sys.stdout
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
```
The last keyword parameter for `print` is the `file` parameter. This defaults to `sys.stdout`, as one would expect, but can be substituted with any object that has a `write` method (or with `None`, to get the default behaviour) In particular, it can be used to produce formatted output for files:
```python
# Re-working the first example.
for recipe in cookbook:
    print(recipe.title, f'${recipe.total_cost * 4:.2f}', file=menu)
    menu.write(chatgpt_rewrite_for_marketing(recipe.description))
    print(f'({recipe.calories} calories)', file=menu)
```
This version takes advantage of the ability to specify multiple outputs at once, and the default `sep` and `end` values.

<details>
<summary>Advanced usage: working with sys.stdout</summary>

Of course, it's also possible to call the `.write` method of `sys.stdout` directly, just as one would with any other file.

It's even possible to *replace* sys.stdout with another object, which will affect future `print` calls. When no `file` argument is provided (or if it's `None`), `print` will look up the *current value* of `sys.stdout` rather than always using the *actual* standard output.

When doing this, it's best to use another variable to "remember" the previous file object, so that it can be restored later:
```
>>> old_stdout = sys.stdout
>>> class devnull: # define a fake "file" type that ignores everything.
...     def write(self, text):
...         pass
... 
>>> sys.stdout = devnull() # make and use a fake
>>> print('This will not be seen')
>>> sys.stdout = old_stdout # good thing we remembered!
>>> print('This will be seen')
This will be seen
```

</details>