Mathew K Analytics

Lesson 22 · Python standard library deep dive

Python io, string & textwrap Explained: Text & Streams | Standard Library #22

Video twenty-two of the twenty-five-part series: io, string, and textwrap, for text and stream utilities. In-memory streams, character-class constants,…

⬇ Download notebookOpen in Colab ↗

📓 Full notebook

Download .ipynb

Python Standard Library Deep-Dive, Video 22: io, string, textwrap#

  • Video twenty-two of the twenty-five-part series: io, string, and textwrap, for text and stream utilities.
  • In-memory streams, character-class constants, template substitution, and text wrapping and formatting.
  • Let's get into it.

Part 1: io.StringIO - In-Memory Text Streams#

import io
buffer = io.StringIO()
buffer.write('first line\n')
buffer.write('second line\n')
print(buffer.getvalue())
buffer.seek(0)
for line in buffer:
    print(repr(line))
first line
second line

'first line\n'
'second line\n'

Part 2: io.BytesIO - In-Memory Binary Streams#

byte_buffer = io.BytesIO()
byte_buffer.write(b'\x89PNG\r\n')
byte_buffer.write(b'more binary data')
print(byte_buffer.getvalue())
byte_buffer.seek(0)
print(byte_buffer.read(4))
print(byte_buffer.read())
b'\x89PNG\r\nmore binary data'
b'\x89PNG'
b'\r\nmore binary data'

Part 3: seek(), tell(), and the File-Like Protocol#

text_buffer = io.StringIO('Hello, World!')
print(text_buffer.tell())
print(text_buffer.read(5))
print(text_buffer.tell())
text_buffer.seek(7)
print(text_buffer.read())
text_buffer.seek(0)
print(text_buffer.read())
0
Hello
5
World!
Hello, World!

Part 4: string Module Constants#

import string
print(string.ascii_lowercase)
print(string.ascii_uppercase)
print(string.digits)
print(string.punctuation)
print(string.whitespace == ' \t\n\r\x0b\x0c')
print(len(string.printable))
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
True
100

Part 5: string.Template - Simple Substitution#

from string import Template
greeting = Template('Hello, $name! You have $count new messages.')
print(greeting.substitute(name='Ana', count=3))
safe_result = greeting.safe_substitute(name='Sam')
print(safe_result)
try:
    greeting.substitute(name='Sam')
except KeyError as e:
    print(f'missing key: {e}')
Hello, Ana! You have 3 new messages.
Hello, Sam! You have $count new messages.
missing key: 'count'

Part 6: string.Formatter - Custom Formatting Behavior#

from string import Formatter
class DefaultFormatter(Formatter):
    def get_value(self, key, args, kwargs):
        if isinstance(key, str) and key not in kwargs:
            return f'<missing:{key}>'
        return super().get_value(key, args, kwargs)
fmt = DefaultFormatter()
print(fmt.format('Hello {name}, balance: {balance}', name='Ana'))
Hello Ana, balance: <missing:balance>

Part 7: textwrap.wrap() and fill()#

import textwrap
long_text = 'Python is a genuinely versatile, widely-used programming language favored for data analysis, automation, and web development.'
lines = textwrap.wrap(long_text, width=40)
for line in lines:
    print(line)
print('---')
print(textwrap.fill(long_text, width=40))
Python is a genuinely versatile, widely-
used programming language favored for
data analysis, automation, and web
development.
---
Python is a genuinely versatile, widely-
used programming language favored for
data analysis, automation, and web
development.

Part 8: textwrap.shorten(), dedent(), and indent()#

print(textwrap.shorten('This sentence is genuinely far too long to display in full', width=30))
messy = '''
    line one
    line two
        line three, extra indented
'''
print(repr(textwrap.dedent(messy)))
print(textwrap.indent('first\nsecond', prefix='>> '))
This sentence is [...]
'\nline one\nline two\n    line three, extra indented\n'
>> first
>> second

Part 9: A Real Pattern - Testing File-Consuming Code with StringIO#

def count_words(file_obj):
    total = 0
    for line in file_obj:
        total += len(line.split())
    return total
fake_file = io.StringIO('the quick fox\njumps over\nthe lazy dog\n')
print(count_words(fake_file))
with open('demo_real_words.txt', 'w') as f:
    f.write('one two three\n')
with open('demo_real_words.txt') as f:
    print(count_words(f))
8
3

Part 10: A Real Pattern - Building a Formatted Text Report#

report_template = Template('=== $title ===\n\n$body\n\nGenerated for: $author')
summary = ('This quarter showed genuinely strong growth across every region, '
           'with particularly notable gains in the data analytics product line '
           'and continued steady demand for the core platform offering.')
wrapped_summary = textwrap.fill(summary, width=50)
final_report = report_template.substitute(
    title='Q3 Summary',
    body=wrapped_summary,
    author='Ana',
)
output = io.StringIO()
output.write(final_report)
output.write('\n')
print(output.getvalue())
=== Q3 Summary ===

This quarter showed genuinely strong growth across
every region, with particularly notable gains in
the data analytics product line and continued
steady demand for the core platform offering.

Generated for: Ana

Wrap-Up: What You Learned#

  • io.StringIO and io.BytesIO provide real in-memory file-like streams, for text and binary respectively.
  • seek/tell work identically on real files and on StringIO/BytesIO; code written against 'any file-like object' works on both.
  • string provides ready-made character-class constants: ascii_letters, digits, punctuation, whitespace, printable.
  • string.Template offers safer plain substitution than f-strings for template text from an untrusted or external source.
  • string.Formatter is the class powering str.format; subclassing it customizes formatting behavior, like handling missing fields.
  • textwrap.wrap/fill break long text into width-limited lines, as a list or as one joined string.
  • textwrap.shorten truncates with a placeholder; dedent strips common leading whitespace; indent adds a prefix per line.
  • A real pattern: testing file-consuming code with StringIO instead of real files, exercising identical code paths.
  • A real pattern: combining Template, textwrap, and StringIO to assemble a formatted text report in memory.
  • That wraps up io, string, and textwrap. Next up: uuid, base64, and binascii, for unique identifiers and encoding.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.