{"id":2472,"date":"2025-09-13T21:57:46","date_gmt":"2025-09-13T13:57:46","guid":{"rendered":"http:\/\/blue.yn.cn\/?p=2472"},"modified":"2025-12-03T10:29:45","modified_gmt":"2025-12-03T02:29:45","slug":"files","status":"publish","type":"post","link":"http:\/\/blue.yn.cn\/?p=2472","title":{"rendered":"7. Files"},"content":{"rendered":"<h3>Persistence<\/h3>\n<p>So far, we have learned how to write programs and communicate our intentions to the Central Processing Unit using conditional execution, funtions, and iterations. We have learned how to create and use data structures in the Main Memory. The CPU and memory are where our software works and runs. It is where all of the &quot;thinking&quot; happens.<\/p>\n<p>But if you recall from hardware architecture discussions, once the power is turned off, anything stored in either the CPU or main memory is erased. So up to now, our programs have just been transient fun exercises to learn Python.<\/p>\n<p><img decoding=\"async\" src=\"\/wp-content\/uploads\/2025\/09\/image-1757816302068.png\" alt=\"file\" \/><\/p>\n<p>Secondary Memory<br \/>\nIn this chapter, we start to work with Secondary Memory (or files). Secondary Memory is not erased when the power is turned off. Or in the case of a USB flash drive, the data we write from our programs can be removed from the system and transported to another system.<\/p>\n<p>We will primarily focus on reading and writing text files such as thoes we create in a text editor. Later we will see how to work with database files which are binary files, specifically designed to be read and written through database software.<\/p>\n<h3>Opening Files<\/h3>\n<p>When we want to read or write a file (say on your hard drive), we first must open the file. Opening the file communicates with your opening system, which knows where the data for each file is stored. When you open a file, you are asking the operating system to find the file by name and make sure the file exists. In this example, we open the file mbox.txt, which should be stored in the same folder that you are in when you start Python. You can download this file from <a href=\"www.py4e.com\/code3\/mbox.txt\">www.py4e.com\/code3\/mbox.txt<\/a><\/p>\n<pre><code class=\"language-python\">>&gt;&gt; fhand = open(&#039;mbox.txt&#039;)\n>&gt;&gt; print(fhand)\n&lt;_io.TextIOWrapper name=&#039;mbox.txt&#039; mode=&#039;r&#039; encoding=&#039;cp1252&#039;&gt;<\/code><\/pre>\n<p>If the <code>open<\/code> is successful, the operating system returns us a file handle. The file handle is not the actual data contained in the file, bu instead it is a &quot;handle&quot; that we can use to read the data. You are given a handle if the requested file exists and you have the proper permissions to read the file.<\/p>\n<p><img decoding=\"async\" src=\"\/wp-content\/uploads\/2025\/09\/image-1757818092739.png\" alt=\"file\" \/><\/p>\n<p>A File Handle<br \/>\nIf the file does not exist, <code>open<\/code> will fail with a traceback and you will not get a handle to access the contents of the file:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; fhand = open(&#039;stuff.txt&#039;)\nTraceback (most recent call last):\nFile &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;\nFileNotFoundError: [Errno 2] No such file or directory: &#039;stuff.txt&#039;<\/code><\/pre>\n<p>Later we will use <code>try<\/code> and <code>except<\/code> to deal more gracefully with the situation where we attempt to open a file that does not exist.<\/p>\n<h3>Text files and lines<\/h3>\n<p>A text file can be thought of as a sequence of lines, much like a Python string can be thought of as a sequence of characters, this is a sample of a text file which records mail activity from various individuals in an open source project development team:<\/p>\n<pre><code class=\"language-python\">From stephen.marquard@uct.ac.za Sat Jan  5 09:14:16 2008\nReturn-Path: &lt;postmaster@collab.sakaiproject.org&gt;\nDate: Sat, 5 Jan 2008 09:12:18 -0500\nTo: source@collab.sakaiproject.org\nFrom: stephen.marquard@uct.ac.za\nSubject: [sakai] svn commit: r39772 - content\/branches\/\nDetails: http:\/\/source.sakaiproject.org\/viewsvn\/?view=rev&amp;rev=39772\n...<\/code><\/pre>\n<p>The entire file of mail interactions is available from<\/p>\n<p><a href=\"www.py4e.com\/code3\/mbox.txt\">www.py4e.com\/code3\/mbox.txt<\/a><\/p>\n<p>and a shortened version of the file is available from<\/p>\n<p><a href=\"www.py4e.com\/code3\/mbox-short.txt\">www.py4e.com\/code3\/mbox-short.txt<\/a><\/p>\n<p>These files are in a standard format for a file containing multiple mail messages. The lines which start with &quot;From&quot; separate the messages and lines which start with &quot;From:&quot; are part of the messages. For more information about mbox format, see<\/p>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Mbox\">https:\/\/en.wikipedia.org\/wiki\/Mbox<\/a><\/p>\n<p>To break the file into lines, there is a special character that represents the &quot;end of the line&quot; called the newline character.<\/p>\n<p>In Python, we represent the newline charater as a backslash-n in string constants. Even though this looks like two characters, it is actually a single character. When we look at the variable by entering &quot;stuff&quot; in th interpreter, it shows us the <code>\\n<\/code> in the string, but when we use <code>print<\/code> to show the string, we see the string broken into two lines by the newline character.<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; stuff = &#039;Hello\\nWorld!&#039;\n>&gt;&gt; stuff\n&#039;Hello\\nWorld!&#039;\n>&gt;&gt; print(stuff)\nHello\nWorld!\n>&gt;&gt; stuff = &#039;X\\nY&#039;\n>&gt;&gt; print(stuff)\nX\nY\n>&gt;&gt; len(stuff)\n3<\/code><\/pre>\n<p>You can also see that the length of the string <code>X\\nY<\/code> is three characters because the newline character is a single charater.<\/p>\n<p>So when we look at the lines in a file, we need to imagine that there is a special invisible character called the newline at the end of each line that marks the end of the line.<\/p>\n<p>So the newline character separates the characters in the file into lines.<\/p>\n<h3>Reading files<\/h3>\n<p>While the file handle does not contain the data for the file, it is quite easy to construct a <code>for<\/code> loop to read through and count each of the lines in a file:<\/p>\n<pre><code class=\"language-python\">fhand = open(&#039;mbox-short.txt&#039;)\ncount = 0\nfor line in fhand:\n    count = count + 1\nprint(&#039;Line Count:&#039;, count)\nLine Count: 2061<\/code><\/pre>\n<p>We can use the file handle as the sequence in our <code>for<\/code> loop. Our <code>for<\/code> loop simply counts the number of lines in the file and prints them out. The rough translation of the <code>for<\/code> loop into English is, &quot;for each line in the file represented by the file handle, add one to the <code>count<\/code> variable.&quot;<\/p>\n<p>The reason that the <code>open<\/code> function does not read the entire file is that the file might be quite large with many gigabytes of data. The <code>open<\/code> statement takes the same amount of time regardless of the size of the file. The <code>for<\/code> loop actually causes the data to be read from the file.<\/p>\n<p>When the file is read using a <code>for<\/code> loop in this manner, Python takes care of splitting the data in the file into separate lines using the newline character. Python reads each line through the newline and includes the newline as the last character in the <code>line<\/code> variable for each iteration of the <code>for<\/code> loop.<\/p>\n<p>Because the <code>for<\/code> loop reads the data one line at a time, it can efficiently read and count the lines in very large files without running out of main memory to store the data. The above program can count the lines in any size file using very little memory since each line is read, counted, and then discarded.<\/p>\n<p>If you know the file is relatively small compared to the size of your main memory, you can read the whole file into one string using the <code>read<\/code> method on the file handle<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; fhand = open(&#039;mbox-short.txt&#039;)\n>&gt;&gt; inp = fhand.read()\n>&gt;&gt; print(len(inp))\n94626\n>&gt;&gt; print(inp[:20])\nFrom stephen.marquar<\/code><\/pre>\n<p>In this example, the entire contents (all 94626 characters) of the file mbox-short.txt are read directly into the variable <code>inp<\/code>. We use string slicing to print out the first 20 characters of the string data stored in <code>inp<\/code>.<\/p>\n<p>When the file is read in this manner, all the characters including all of the lines and newline characters are one big string in the variable <code>inp<\/code>. It is a good idea to store the output of <code>read<\/code> as a variable because each call to <code>read<\/code> exhausts the resource:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; fhand = open(&#039;mbox-short.txt&#039;)\n>&gt;&gt; print(len(fhand.read()))\n94626\n>&gt;&gt; print(len(fhand.read()))\n0<\/code><\/pre>\n<p>Remember that this form of the <code>open<\/code> function should only be used if the file data will fit comfortably in the main memory of your computer. If the file is too large to fit in main memory, you should write your program to read the file in chunks using a <code>for<\/code> or <code>while<\/code> loop.<\/p>\n<h3>Searching through a file<\/h3>\n<p>When you are searching through data in a file, it is a very common patterns to read through a file, ignoring most of the lines and only processing lines which meet a particular condition. We can combine the pattern for reading a file with string method to build simple search mechanisms.<\/p>\n<p>For example, if we wanted to read a file and only print out lines which started with the prefix &quot;From:&quot;, we could use the string method startwith to select only those lines with the desired prefix:<\/p>\n<pre><code class=\"language-python\">fhand = open(&#039;mbox-short.txt&#039;)\nfor line in fhand:\n    if line.startswith(&#039;From:&#039;):\n        print(line)<\/code><\/pre>\n<p>When this program runs, we get the following output:<\/p>\n<pre><code class=\"language-python\">From: stephen.marquard@uct.ac.za\n\nFrom: louis@media.berkeley.edu\n\nFrom: zqian@umich.edu\n\nFrom: rjlowe@iupui.edu\n...<\/code><\/pre>\n<p>The output looks great since the only lines we are seeing are those which start with &quot;From:&quot;, but why are we seeing the extra blank lines? This is due to that invisible newline character. Each of the lines ends with a newline, so the <code>print<\/code> statement prints the string in the variable line which includes a newline and then <code>print<\/code> adds another newline, resulting in the double spacing effect we see.<\/p>\n<p>We would use line slicing to print all but the last character, but a simpler approach is to use the rstrip method which strips whitespaces from the right side of a string as follows:<\/p>\n<pre><code class=\"language-python\">fhand = open(&#039;mbox-short.txt&#039;)\nfor line in fhand:\n    line = line.rstrip()\n    if line.startswith(&#039;From:&#039;):\n        print(line)<\/code><\/pre>\n<p>When this program runs, we get the following output:<\/p>\n<pre><code class=\"language-python\">From: stephen.marquard@uct.ac.za\nFrom: louis@media.berkeley.edu\nFrom: zqian@umich.edu\nFrom: rjlowe@iupui.edu\nFrom: zqian@umich.edu\nFrom: rjlowe@iupui.edu\nFrom: cwen@iupui.edu\n...<\/code><\/pre>\n<p>As your file processing programs get more complicated, you may want to structure your search loops using <code>continue<\/code>. The basic idea of the search loop is that you are looking for &quot;intersting&quot; lines and effectively skipping &quot;unintersting&quot; lines. And then when we find an intersting line, we do something with that line.<\/p>\n<p>We can structure the loop to follow the pattern of skipping unintersting lines as follows:<\/p>\n<pre><code class=\"language-python\">fhand = open(&#039;mbox-short.txt&#039;)\nfor line in fhand:\n    line = line.rstrip()\n    # Skip &#039;uninteresting lines&#039;\n    if not line.startswith(&#039;From:&#039;):\n        continue\n    # Process our &#039;interesting&#039; line\n    print(line)<\/code><\/pre>\n<p>The output of the program is the same. In English, the uninteresting lines are those which do not start with &quot;From:&quot;, which we skip using <code>continue<\/code>. For the &quot;interesting&quot; lines (i.e., those that start with &quot;From:&quot;) we perform the processing.<\/p>\n<p>We can use the <code>find<\/code> string method to simulate a text editor search that finds lines where the search string is anywhere in the line. Since <code>find<\/code> looks for an occurrence of a string with another string and either returns the position of the string or -1 if the string was not found, we can write the following loop to show lines which contain the string &quot;@uct.ac.za&quot; (i.e., they come from the University of Cape Town in South Africa):<\/p>\n<pre><code class=\"language-python\">fhand = open(&#039;mbox-short.txt&#039;)\nfor line in fhand:\n    line = line.rstrip()\n    if line.find(&#039;@uct.ac.za&#039;) == -1: continue\n    print(line)<\/code><\/pre>\n<p>Which produces the following output:<\/p>\n<pre><code class=\"language-python\">From stephen.marquard@uct.ac.za Sat Jan  5 09:14:16 2008\nX-Authentication-Warning: set sender to stephen.marquard@uct.ac.za using -f\nFrom: stephen.marquard@uct.ac.za\nAuthor: stephen.marquard@uct.ac.za\nFrom david.horwitz@uct.ac.za Fri Jan  4 07:02:32 2008\nX-Authentication-Warning: set sender to david.horwitz@uct.ac.za using -f\nFrom: david.horwitz@uct.ac.za\nAuthor: david.horwitz@uct.ac.za\n...<\/code><\/pre>\n<p>Here we also use the contracted form of the <code>if<\/code> statement where we put the <code>continue<\/code> on the same line as the <code>if<\/code>. This contracted form of the <code>if<\/code> functions the same as if the <code>continue<\/code> were on the next line and indented.<\/p>\n<h3>Letting the user choose the file name<\/h3>\n<p>We really do not want to have to edit our Python code every time we want to process a different file. It would be more usable to enter the file name string each time the program runs so they can use our program on different files without changing the Python code.<\/p>\n<p>This is quite simple to do by reading the file name from the user using <code>input<\/code> as follows:<\/p>\n<pre><code class=\"language-python\">fname = input(&#039;Enter the file name: &#039;)\nfhand = open(fname)\ncount = 0\nfor line in fhand:\n    if line.startswith(&#039;Subject:&#039;):\n        count = count + 1\nprint(&#039;There were&#039;, count, &#039;subject lines in&#039;, fname)<\/code><\/pre>\n<p>We read the file name from the user and place it in a variable named <code>fname<\/code> and open that file. Now we can run the program repeatedly on different files.<\/p>\n<pre><code class=\"language-python\">Enter the file name: mbox.txt\nThere were 1797 subject lines in mbox.txt\n\nEnter the file name: mbox-short.txt\nThere were 27 subject lines in mbox-short.txt<\/code><\/pre>\n<p>Before peeking at the next section, take a look at the above program and ask yourself, &quot;What could go possibly wrong here?&quot; or &quot;What might our friendly user do that would cause our nice little program to ungracefully exit with a traceback, making us look not-so-cool in the eyes of our users?&quot;<\/p>\n<p>Using <code>try, except,<\/code> and <code>open<\/code><\/p>\n<p>I told you not to peek. This is your last chance.<\/p>\n<p>What if our user types something that is not a file name?<\/p>\n<pre><code class=\"language-bash\">Enter the file name: missing.txt\nTraceback (most recent call last):\n  File &quot;search6.py&quot;, line 2, in &lt;module&gt;\n    fhand = open(fname)\nFileNotFoundError: [Errno 2] No such file or directory: &#039;missing.txt&#039;\n\nEnter the file name: na na boo boo\nTraceback (most recent call last):\n  File &quot;search6.py&quot;, line 2, in &lt;module&gt;\n    fhand = open(fname)\nFileNotFoundError: [Errno 2] No such file or directory: &#039;na na boo boo&#039;<\/code><\/pre>\n<p>Do not laugh. Users will eventually do every possible thing they can do to break your prorams, either mistakeenly or with malicious intent. As a matter of fact, an important part of any software development team is a person or group called Quality Assurance (or QA for short) whoese very job it is to do the craziset things possible in an attempt to break the software that the programer has created.<\/p>\n<p>The QA team is responsible for finding the flaws in programs before we have deliverd the program to the end users who may be purchasing the software or paying our salary to write the software. So the QA team is the programmer's best friend.<\/p>\n<p>So now that we see the flaw in the program, we can elegantly fix it using the <code>try<\/code>\/<code>except<\/code> structure. We need to assume that the <code>open<\/code> call might fail and add recovery code when the <code>open<\/code> fails as follows:<\/p>\n<pre><code class=\"language-bash\">fname = input(&#039;Enter the file name: &#039;)\ntry:\n    fhand = open(fname)\nexcept:\n    print(&#039;File cannot be opened:&#039;, fname)\n    exit()\ncount = 0\nfor line in fhand:\n    if line.startswith(&#039;Subject:&#039;):\n        count = count + 1\nprint(&#039;There were&#039;, count, &#039;subject lines in&#039;, fname)<\/code><\/pre>\n<p>The <code>exit<\/code> function terminates the program. It is a function that we call never returns. Now when our user (or QA team) types in silliness or bad file names, we &quot;catch&quot; them and recover gracefully:<\/p>\n<pre><code class=\"language-bash\">Enter the file name: mbox.txt\nThere were 1797 subject lines in mbox.txt\n\nEnter the file name: na na boo boo\nFile cannot be opened: na na boo boo<\/code><\/pre>\n<p>Protecting the <code>open<\/code> call is a good example of the proper use of <code>try<\/code> and <code>except<\/code> in a Python program. We use the term &quot;pythonic&quot; when we are doing something the &quot;Python way&quot;. We might say that the above exampls is the Pythonic way to open a file.<\/p>\n<p>Once you become more skilled in Python, you can engage in repartee with other Python programmers to decide wich of two equivalent solutions to a problem is &quot;more Pythonic&quot;. The goal to be &quot;more Pythonic&quot; captures the notion that programmer is part engineering and part art. We are not always interested in just making something work, we also want our solution to be elegant and to be appriciented as elegant by our peers.<\/p>\n<h3>Writing files<\/h3>\n<p>To write a file, you have to open it with mode &quot;w&quot; as a second parameter:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; fout = open(&#039;output.txt&#039;, &#039;w&#039;)\n>&gt;&gt; print(fout)\n&lt;_io.TextIOWrapper name=&#039;output.txt&#039; mode=&#039;w&#039; encoding=&#039;cp1252&#039;&gt;<\/code><\/pre>\n<p>If the file already exists, opening it in write mode clears out the old data and starts fresh, so be careful! If the file doest exist, a new one is created.<\/p>\n<p>The <code>write<\/code> method of the file handle object puts data into the file, returning the number of  characters written. The default write mode is text for writing (and reading) strings.<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; line1 = &quot;This here&#039;s the wattle,\\n&quot;\n>&gt;&gt; fout.write(line1)\n24<\/code><\/pre>\n<p>Again, the file object keeps track of where it is, so if you call <code>write<\/code> again, it adds the new data to the end.<\/p>\n<p>We must make sure to manage the ends of lines as we write to the file by explicitly inserting the newline character when we want to end a line. The <code>print<\/code> statement automatically appends a newline, but the <code>write<\/code> method does not add the newline automatically.<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; line2 = &#039;the emblem of our land.\\n&#039;\n>&gt;&gt; fout.write(line2)\n24<\/code><\/pre>\n<p>when you are done writing, you have to close the file to make sure that the last bit of data is physically written to the disk so it will not be lost if the power goes off.<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; fout.close()<\/code><\/pre>\n<p>we could close the files wich we open for read as well, but we can be a little sloppy if we are only opening a few files since Python makes sure that all open files are close when the program ends. when we are writing files, we want to explicitlly close the files so as to leave nothing to chance.<\/p>\n<h3>Debugging<\/h3>\n<p>When you are reading and writing files, you might run into problems with whitespace. These errors can be hard to debug because spaces, tabs, and newlines are normally invisible:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; s = &#039;1 2\\t 3\\n 4&#039;\n>&gt;&gt; print(s)\n1 2  3\n 4<\/code><\/pre>\n<p>The built-in function <code>repr<\/code> can help. It takes any object as an argument and returns a string representation of the object. For strings, it reprsents whitespace characters with backslash sequences:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; print(repr(s))\n&#039;1 2\\t 3\\n 4&#039;<\/code><\/pre>\n<p>This can be helpful for debugging.<\/p>\n<p>One other problem you might run into is that different systems use different characters to indicate the end of a line. Some systems use a newline, represented <code>\\n<\/code>. Other use a return character, represented <code>\\r<\/code>. Some use both. If you move files between different systems, these inconsistencies might cause problems.<\/p>\n<p>For most systems, there are applications to convert from one form to another. You can find them (and read more about this issue) at <a href=\"https:\/\/www.wikipedia.org\/wiki\/Newline\">https:\/\/www.wikipedia.org\/wiki\/Newline<\/a>. Or, of couse, you could write one yourself.<\/p>\n<h3>Glassary<\/h3>\n<p><strong>catch<\/strong><br \/>\nTo prevent an exception from terminating a program using the <code>try<\/code> and <code>except<\/code> statements.<\/p>\n<p><strong>newline<\/strong><br \/>\nA special character used in files and string to indicate the end of a line.<\/p>\n<p><strong>Python<\/strong><br \/>\nA technique that works elegantly in Python. &quot;using try and except is the Pythonic way to recover from missing files&quot;<\/p>\n<p><strong>Quality Assurance<\/strong><br \/>\nA person or team focused on insuring the overall quality of a software product. QA is often involved in testing a product and identifying problems before the product is released.<\/p>\n<p><strong>text file<\/strong><br \/>\nA sequence of characters stored in permanent storage like a hard drive.<\/p>\n<h3>Exercises<\/h3>\n<p><strong>Exercise 1:<\/strong> Write a program to read through a file and print the contents of the file (line by line) all in upper case. Executing the program will look as follows:<\/p>\n<pre><code class=\"language-python\">fname = input(&#039;Enter file name: &#039;)\ntry:\n    fhand = open(fname,encoding=&#039;utf-8&#039;)\nexcept:\n    print(&#039;please enter a valid file&#039;)\n    exit()\nfor line in fhand:\n    print(line.upper())<\/code><\/pre>\n<pre><code class=\"language-python\"># generated by AI code\n# \u63d0\u793a\u7528\u6237\u8f93\u5165\u6587\u4ef6\u540d\nfname = input(&#039;Enter a file name: &#039;)\n\n# \u5f02\u5e38\u5904\u7406\uff1a\u6355\u83b7\u6587\u4ef6\u4e0d\u5b58\u5728\u7b49\u9519\u8bef\ntry:\n    # \u6253\u5f00\u6587\u4ef6\u5e76\u9010\u884c\u8bfb\u53d6\n    with open(fname, &#039;r&#039;) as fhand:\n        # \u904d\u5386\u6587\u4ef6\u7684\u6bcf\u4e00\u884c\n        for line in fhand:\n            # \u53bb\u9664\u884c\u5c3e\u6362\u884c\u7b26\uff0c\u8f6c\u6362\u4e3a\u5927\u5199\u540e\u6253\u5370\n            line_upper = line.rstrip().upper()\n            print(line_upper)\n# \u5904\u7406\u6587\u4ef6\u65e0\u6cd5\u6253\u5f00\u7684\u60c5\u51b5\nexcept:\n    print(f&#039;Error: Cannot open file &quot;{fname}&quot;&#039;)\n    exit()<\/code><\/pre>\n<p>You can download the file from <a href=\"www.py4e.com\/code3\/mbox-short.txt\">www.py4e.com\/code3\/mbox-short.txt<\/a><\/p>\n<p><strong>Exercise 2:<\/strong> Write a program to prompt for a file name, and then read through the file and look for lines of the form:<\/p>\n<pre><code class=\"language-python\">X-DSPAM-Confidence: 0.8475<\/code><\/pre>\n<p>When you encounter a line that starts with &quot;X-DSPAM-Confidence:&quot; pull apart the line to extract the floating-point number on the line. Count these lines and then compute the total of the spam confidence values from these lines. When you reach the end of the file, print out the average spam confidence.<\/p>\n<pre><code class=\"language-python\">fname = input(&#039;Enter file name: &#039;)\ntry:\n    fhand = open(fname,encoding=&#039;utf-8&#039;)\nexcept:\n    print(&#039;please enter a valid file&#039;)\n    exit()\ncount = 0\ntotal = 0\nfor line in fhand:\n    words = line.split()\n    if len(words) != 2: continue\n    if words[0] != &#039;X-DSPAM-Confidence:&#039;: continue\n    conf = float(words[1])\n    total = total + conf\n    count = count + 1\naverage = total\/count\nprint(&#039;Average spam confidence:&#039;, average)\n\nEnter file name: mbox-short.txt\nAverage spam confidence: 0.7507185185185187<\/code><\/pre>\n<p>Test your file on the mbox.txt and mbox-short.txt files.<\/p>\n<p><strong>Exercise 3:<\/strong><br \/>\nSometimes when programmers get bored or want to have a bit of fun, they add a harmless Easter Egg to their program. Modify the program that prompts the user for the file name so that it prints a funny message when the user types in the exact file name &quot;na na boo boo&quot;. The program should bahave normally for other files wich exist and don't exist. Here is a sample execution of the program:<\/p>\n<pre><code class=\"language-python\">Enter the file name: mbox.txt\nThere were 1797 subject lines in mbox.txt\n\nEnter the file name: missing.txt\nFile cannot be opened: missing.t```python\nfname = input(&#039;Enter file name: &#039;)\nif fname == &#039;na na boo boo&#039;:\n    print(&#039;NA NA BOBO TO YOU - You have bee punkd!&#039;)\n    exit()\ntry:\n    fhand = open(fname, encoding=&#039;utf-8&#039;)\nexcept:\n    print(&#039;File cannot be opened:&#039;, fname)\n    exit()\ncount = 0\nfor line in fhand:\n    if line.startswith(&#039;Subject&#039;):\n        count = count + 1\nprint(&#039;There were&#039;, count, &#039;subject lines in&#039;, fname)<\/code><\/pre>\n<pre><code class=\"language-python\">Enter the file name: na na boo boo\nNA NA BOO BOO TO YOU - You have been punk&#039;d!<\/code><\/pre>\n<p>We are not encouraging you to put East Eggs in your programs; this is just an exercise.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Persistence So far, we have learned how to write progra&#8230; &raquo; <a class=\"read-more-link\" href=\"http:\/\/blue.yn.cn\/?p=2472\">\u9605\u8bfb\u5168\u6587<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24],"tags":[],"class_list":["post-2472","post","type-post","status-publish","format-standard","hentry","category-python"],"_links":{"self":[{"href":"http:\/\/blue.yn.cn\/index.php?rest_route=\/wp\/v2\/posts\/2472","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blue.yn.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blue.yn.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blue.yn.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blue.yn.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2472"}],"version-history":[{"count":17,"href":"http:\/\/blue.yn.cn\/index.php?rest_route=\/wp\/v2\/posts\/2472\/revisions"}],"predecessor-version":[{"id":2626,"href":"http:\/\/blue.yn.cn\/index.php?rest_route=\/wp\/v2\/posts\/2472\/revisions\/2626"}],"wp:attachment":[{"href":"http:\/\/blue.yn.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2472"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blue.yn.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2472"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blue.yn.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2472"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}