Writing Files¶

🎨 open(..., 'w')¶

In [ ]:
# see the file write_example.py
with open('write_example.txt', 'w') as file:
    file.write('Hello?\n')

write.py¶

NOTES

  • After running the code, look for write_example.txt and examine its contents
  • Delete the file and run the code again -> the file is back!
In [ ]:
%%file write_more.py
with open('write_example.txt', 'w') as file:
    file.write('Hello world!\n')
    file.write('The ability to write files seems like it might be useful.\n')

write_more.py¶

NOTES

  • After running the code, look for write_example.txt and examine its contents
  • The contents have changed! What happened to the old contents...?
    • They are GONE.

boring_file.txt¶

In [ ]:
%%file boring_file.txt
This is a boring file.
It needs some pizzaz.
Like bullets at the front of each line. 
In [ ]:
%%file make_exciting.py
with open('boring_file.txt') as infile:
    with open('exciting_file.txt', 'w') as outfile:
        for line in infile:
            outfile.write('⭐️ ')
            outfile.write(line)
In [ ]:
! cat exciting_file.txt
In [ ]:
! cat boring_file.txt

NOTES

  • Demonstrate the contents of boring_file.txt
  • Run the code, look at exciting_file.txt
  • Add 'w' to the open of boring_file.txt
    • The code fails. Oops.
    • Remove the 'w' and run it again. It appears to work.
    • Look at excting_file.txt. It is empty!
    • Look at boring_file.txt. It is empty!!
In [ ]:
# Problem code!

with open('boring_file.txt', 'w') as infile:
    with open('exciting_file.txt', 'w') as outfile:
        for line in infile:
            outfile.write('⭐️ ')
            outfile.write(line)

When you open an existing file for writing, the original contents are DELETED.

😳

With great power comes great responsibility

Measure twice, cut once.

Always double check the file you are opening before you run your code.
Never write to the wrong file!
Always store a backup of important files you will touch with code!

NOTES

  • Guess who managed to accidentally delete (i.e. overwite with nonsense data) 100's of GB of image data at his first job out of grad school?

Lines¶

In [ ]:
%%file write_lines.py
with open('another_example.txt', 'w') as file:
    file.write('First line.')
    file.write('Second line.')
    file.write('Third line.')

write_lines.py¶

NOTES

  • Run write_lines.py
  • Look at another_example.txt
  • What happened here?
    • There are no newlines.
  • Add in file.write('\n')
In [ ]:
with open('another_example.txt', 'w') as file:
    file.write('First line.')
    file.write('\n')
    file.write('Second line.')
    file.write('\n')
    file.write('Third line.')
    file.write('\n')
    
  • If the strings you are writing already have newlines at the end, you don't need to add extra newlines.
  • If the strings don't already have newlines, and you want newlines, you need to add them.

NOTES

  • If the strings you are already writing have newlines, you don't need to add them
  • If they don't, you'll need to include them
  • Unless you don't want newlines.
  • You'll know the situation and the desired outcome. Act accordingly.

🖌 String interpolation¶

interpolation: the insertion of something into something else

In [ ]:
name = 'Dr. Bean'
print(f'Hello, my name is {name}')

NOTES

  • {...} allow you to include any expression. The resulting value will be turned into a string an included at that location.
  • f at the beginning is important. What happens without it?
In [ ]:
def print_info(name, age, favorite_pizza):
    print(f"{name} is {age} years old. \n{name}'s favorite pizza is {favorite_pizza}. 🍕")
    
In [ ]:
print_info()
In [ ]:
print_info()
In [ ]:
print_info('Jon', 21, "buffalo chicken")  # <- Fill in
In [ ]:
print_info('Wyatt', 22, 'pepperoni')  # <- Fill in
In [ ]:
print_info('Gordon', 38, 'alfredo hawaiian')

Given a name, pronoun, major, and hometown, write a function that would write out the information in the following format:

Alice is from Beaverdam. 
At BYU, she is majoring in Sociology.
Do you know anyone else from Beaverdam?
In [ ]:
def print_info(name, pronoun, major, hometown):
    pass
    
print_info('Alice', 'she', 'Sociology', 'Beaverdam')
In [ ]:
# Solution
def print_info(name, pronoun, major, hometown):
    print(f'{name} is from {hometown}.')
    print(f'At BYU, {pronoun} is majoring in {major}.')
    print(f'Do you know anyone else from {hometown}?')
    
print_info('Alice', 'she', 'Sociology', 'Beaverdam')

Now lets write that to a file instead of printing it to the console.

In [ ]:
def print_info(file, name, pronoun, major, hometown):
    file.write(f"{name} is from {hometown}.\nAt BYU, {pronoun} is majoring in {major}.\n")
    file.write(f"Do you know anyone else from {hometown}?\n")
    
with open('information.txt', 'w') as outfile:
    print_info(outfile, 'Jason', 'he', 'Computer Science', 'someplace in Alaska 🥶')
    print_info(outfile, 'Isabella', 'she', 'Computer Science', 'Arizona 🥵')
    
with open('information.txt') as infile:
    for line in infile:
        print(line)
In [ ]:
# Solution

def print_info(file, name, pronoun, major, hometown):
    file.write(f'{name} is from {hometown}.\n')
    file.write(f'At BYU, {pronoun} is majoring in {major}.\n')
    file.write(f'Do you know anyone else from {hometown}?\n')
    
with open('all_about_alice.txt', 'w') as file:
    print_info(file, 'Alice', 'she', 'Sociology', 'Beaverdam')

Do you pass a file name to print_info or a file handle?

NOTES

  • We could have had print_info open a file
  • But we like to have functions focus on only one job
  • print_info is focused on writing specific information
  • We let some other part of the code decide where that information gets written

  • Demonstrate how we can easily add information for more students to the same file.

Deciding the respective responsibilities of the different parts of your code is an art. Seek to learn the beauty of that art.

When writing numbers to a file...¶

In [ ]:
with open('numbers.txt', 'w') as file:
    number = 42
    file.write(f"the number is {number}")
    file.write('\n')

NOTES

  • You have to convert your data to strings before you can write it to a file.

🖌 Indexing¶

In addition to iterating over all the elements of a list, it is also helpful to be able to access a specific element, like the first, or third.

In [ ]:
fruits = ['apples', 'peaches', 'strawberries', 'plums']
In [ ]:
fruits[3]
In [ ]:
fruits[0]
In [ ]:
fruits[3]

NOTES

  • Syntax: [] immediately following a list, with an integer inside.
  • The first element in the list is indexed by [0], not by [1]
    • we call this 0-based indexing.
      • C, C++, Java, C#, JavaScript and more use 0-based indexing
    • some languages use 1-based indexing.
    • there are pros and cons to both approaches.
  • In 0-based indexing, the index of the last item will be $length - 1$
In [ ]:
fruits[2.5]
In [ ]:
fruits[]
In [ ]:
len(fruits)
In [ ]:
fruits[4]

NOTES

  • With 0-based indexing, the position of the last element will be $length - 1$
With 0-based indexing, the position of the last element will be length - 1

🖌 sys.argv¶

argv_demo.py¶

In [ ]:
! python argv_demo.py

NOTES

  • the first entry (i.e. index 0) contains the name of the python script
In [ ]:
! python argv_demo.py and some more stuff

👨🏼‍🎨 copy_file.py¶

Write a program that copies a file.

For example,

python copy_file.py some_file.txt another_file.txt

should write a file named another_file.txt that has a copy of the contents of some_file.txt.

NOTES

  • Write copy_file.py
  • Deal with extra newlines from print
  • Take the arguments from sys.argv - get index 1 and 2, not index 0 and 1
  • DRAW IT OUT
    • Demonstrate how to draw out this kind of problem:
      • dataflow diagram
      • what kinds of data do you have at each step?
      • what operations transition the data from one step to another?
  • Run the script on several inputs (including itself: python copy_file.py copy_file.py copy_again.py)
In [ ]:
%%file contents.txt
This file has stuff in it.
Stuff that you'd probably like more copies of.
If only you had a program that could copy files...
In [ ]:
import sys

def read_lines(filename):
    with open(filename) as file:
        return list(file)
    
def write_lines(filename, lines):
    with open(filename, 'w') as file:
        for line in lines:
            file.write(line)
        
def main(input_file, output_file):
    lines = read_lines(input_file)
    write_lines(output_file, lines)
    
main(sys.argv[1], sys.argv[2])
In [ ]:
!python copy_file.py contents.txt more_contents.txt
In [ ]:
! cat more_contents.txt

Key Ideas¶

  • open(..., 'w') for writing to a file
  • Opening a file for writing deletes any original contents
  • '\n' represents the newline character
  • f'...{...}...' string interpolation
  • Indexing my_list[...]
    • 0-based
    • access any specific element of a list
  • sys.argv