.. _ch05-python-IO: =============================================================== Recap & Outlook =============================================================== Google drive folder with Jupyter Notebooks used in class: `Jupyter Notebooks from class `_ So far, we have learned how to use Python for programming, with a focus on Python's basic data types, modules, built-in functions. Then we looked at the numerical capabilities provided by NumPy, plotting with Matplotlib, as well as more specialized tasks with SymPy and SciPy. In this short chapter we will extend our knowledge a bit further so that we can use Python to #. Read and write files #. Interact with the operating system #. Debug more efficiently #. Approach problems using object-oriented programming =============================================================== Reading Materials =============================================================== The materials of this chapter in part have been adopted and modified from: * `Think Python by Allen B. Downey `_, * `Prof. LeVeque's (Univ. of Washington) online note on Python `_. =============================================================== Python input and output =============================================================== ------------------------------------------------------------------------------- Reading and writing files ------------------------------------------------------------------------------- Reading and writing to files from Python is most easily done through strings. Binary data, and non-human-readable files can be generated, but will not be considered here. Opening and closing a file is as simple as: .. code-block:: python >>> f = open('output','w') >>> type(f) _io.TextIOWrapper >>> f.write('Welcome to AM 129\nwe love scientific computing!') 47 # the number of characters, including whitespace, that was written >>> f.close() Note that the ``'w'`` in the ``open`` function indicates that we are opening this file in *write* mode. Furthermore, note that we need to close the file when we are done with it (more on this later). To read from a file .. code-block:: python >>> f = open('output','r') >>> contents = f.read() >>> print(contents) Welcome to AM 129 we love scientific computing! >>> f.close() Note that the ``'w'`` flag will not just open a file for writing, but will also clear the contents of that file. If you want to add to the current contents, open the file with mode ``'a'`` to *append* .. code-block:: python >>> f = open('output','w') >>> f.write('Welcome to AM 129 \nwe love scientific computing!') >>> f.close() >>> f = open('output','a') >>> f.write('\nPython is fun to learn') 23 >>> f.close() To see how it is changed now .. code-block:: python >>> f = open('output','r') >>> contents = f.read() >>> print(contents) Welcome to AM 129 we love scientific computing! Python is fun to learn >>> f.close() See also For more details: https://docs.python.org/tutorial/inputoutput.html ------------------------------------------------------------------------------- Iterating over lines in a file ------------------------------------------------------------------------------- A file can be used as an iterable in Python .. code-block:: python >>> f=open('output','r') >>> for line in f: ... print(line) ... Welcome to AM 129 we love scientific computing! Python is fun to learn >>> f.close() You may notice that a blank line has been inserted in every ``line`` variable. This is because the escape character, ``\n``, is recognized as a blank line. If you want to delete the escape character, you may use the ``strip`` method. .. code-block:: python >>> f = open('output', 'r') >>> for line in f: ... print(line.strip()) ... Welcome to AM 129 we love scientific computing! Python is fun to learn If you repeat this loop a second time you won't get any output: .. code-block:: python >>> f = open('output', 'r') >>> for line in f: ... print(line.strip()) ... >>> f.close() Why is this? You can reset yourself to the beginning of the file by calling ``f.seek(0)``. Alternatively, you can read the entire file into a list of strings, each corresponding to one line: .. code-block:: python >>> f = open('output', 'r') >>> lines = f.readlines() >>> f.close() >>> for line in lines: ... print(line.strip()) ... Welcome to AM 129 we love scientific computing! Python is fun to learn If we try to read from, or write to, the file after closing it we will get an error message: .. code-block:: console >>> f.close() >>> for line in f: ... print(line) ... Traceback (most recent call last): File "", line 1, in ValueError: I/O operation on closed file ------------------------------------------------------------------------------- File modes ------------------------------------------------------------------------------- The ``open`` function takes at least one argument, but most typically two. The first must always be the file name. The second is the *mode*, the most common choices of which are: * Read-only: ``r`` * Write-only: ``w`` * Append: ``a`` * Read and Write: ``r+`` * Binary mode: ``b`` You can see other modes, and a slew of other options, by calling ``help(open)``. ------------------------------------------------------------------------------- ``with`` statement ------------------------------------------------------------------------------- In the previous examples, you may have noticed that the general code structure of file input/output in Python. For example, .. code-block:: python f=open(file_name, file_mode) # Do something with file as f f.close() Technically, you don't need to close the file. When your python script is done running the Python interpreter will close the file automatically, even without calling ``close``. However, by writing the ``close`` statement, your code is easier to follow, and more importantly it prevents a host of possible errors. Forgetting to close files is a common bug, and Python provides a nice usage pattern that avoids this issue altogether. The ``with`` statement will automatically close the file after its body has been executed: .. code-block:: python >>> with open(file_name, file_mode) as f: ... for line in f: ... print(line.strip()) >>> f.closed True Isolating all of your file handling in such blocks is **strongly recommended**. As an aside, ``with`` statements have broader uses than just isolating file operations. Any class that implements the `context manager `_ interface can be used with ``with`` statements. ------------------------------------------------------------------------------- Command line arguments ------------------------------------------------------------------------------- Recall from the plotting section that the script ``gpplot.py`` took in several arguments from the command line. This followed the typical pattern shown here: .. code-block:: console $ python your_python_program.py Argument1 Argument2 To access these arguments within a python script you can use the ``sys`` module. ``Argument1`` and ``Argument2`` will become available as: .. code-block:: python import sys arg1 = sys.argv[1] arg2 = sys.argv[2] ... where the first command line argument is ``sys.argv[1]``. Hold on, doesn't Python use 0-based indexing? What is ``sys.argv[0]``? This entry is the name of your program itself. Consider: .. literalinclude:: ./codes/sys_arg.py :language: python :linenos: :download:`Download this code <./codes/sys_arg.py>` Executing this script should generate the following: .. code-block:: console $ python sys_arg.py aa bb cc sys_arg.py aa bb cc ------------------------------------------------------------------------------- Exercise ------------------------------------------------------------------------------- 1. Write a simple Python routine in that creates ``n`` files in with names ``junk_1.txt``, ..., ``junk_n.txt``, each of which contains its filename as content, e.g., ``This is junk_5.txt``. 2. Write a simple routine that reads the files you just created, and prints their contents to the screen.