Python open error codes

8. Errors and Exceptions¶

Until now error messages haven’t been more than mentioned, but if you have tried out the examples you have probably seen some. There are (at least) two distinguishable kinds of errors: syntax errors and exceptions.

8.1. Syntax Errors¶

Syntax errors, also known as parsing errors, are perhaps the most common kind of complaint you get while you are still learning Python:

The parser repeats the offending line and displays a little ‘arrow’ pointing at the earliest point in the line where the error was detected. The error is caused by (or at least detected at) the token preceding the arrow: in the example, the error is detected at the function print() , since a colon ( ‘:’ ) is missing before it. File name and line number are printed so you know where to look in case the input came from a script.

8.2. Exceptions¶

Even if a statement or expression is syntactically correct, it may cause an error when an attempt is made to execute it. Errors detected during execution are called exceptions and are not unconditionally fatal: you will soon learn how to handle them in Python programs. Most exceptions are not handled by programs, however, and result in error messages as shown here:

The last line of the error message indicates what happened. Exceptions come in different types, and the type is printed as part of the message: the types in the example are ZeroDivisionError , NameError and TypeError . The string printed as the exception type is the name of the built-in exception that occurred. This is true for all built-in exceptions, but need not be true for user-defined exceptions (although it is a useful convention). Standard exception names are built-in identifiers (not reserved keywords).

The rest of the line provides detail based on the type of exception and what caused it.

The preceding part of the error message shows the context where the exception occurred, in the form of a stack traceback. In general it contains a stack traceback listing source lines; however, it will not display lines read from standard input.

Built-in Exceptions lists the built-in exceptions and their meanings.

8.3. Handling Exceptions¶

It is possible to write programs that handle selected exceptions. Look at the following example, which asks the user for input until a valid integer has been entered, but allows the user to interrupt the program (using Control — C or whatever the operating system supports); note that a user-generated interruption is signalled by raising the KeyboardInterrupt exception.

The try statement works as follows.

First, the try clause (the statement(s) between the try and except keywords) is executed.

If no exception occurs, the except clause is skipped and execution of the try statement is finished.

If an exception occurs during execution of the try clause, the rest of the clause is skipped. Then, if its type matches the exception named after the except keyword, the except clause is executed, and then execution continues after the try/except block.

If an exception occurs which does not match the exception named in the except clause, it is passed on to outer try statements; if no handler is found, it is an unhandled exception and execution stops with a message as shown above.

A try statement may have more than one except clause, to specify handlers for different exceptions. At most one handler will be executed. Handlers only handle exceptions that occur in the corresponding try clause, not in other handlers of the same try statement. An except clause may name multiple exceptions as a parenthesized tuple, for example:

A class in an except clause is compatible with an exception if it is the same class or a base class thereof (but not the other way around — an except clause listing a derived class is not compatible with a base class). For example, the following code will print B, C, D in that order:

Note that if the except clauses were reversed (with except B first), it would have printed B, B, B — the first matching except clause is triggered.

When an exception occurs, it may have associated values, also known as the exception’s arguments. The presence and types of the arguments depend on the exception type.

The except clause may specify a variable after the exception name. The variable is bound to the exception instance which typically has an args attribute that stores the arguments. For convenience, builtin exception types define __str__() to print all the arguments without explicitly accessing .args .

The exception’s __str__() output is printed as the last part (‘detail’) of the message for unhandled exceptions.

BaseException is the common base class of all exceptions. One of its subclasses, Exception , is the base class of all the non-fatal exceptions. Exceptions which are not subclasses of Exception are not typically handled, because they are used to indicate that the program should terminate. They include SystemExit which is raised by sys.exit() and KeyboardInterrupt which is raised when a user wishes to interrupt the program.

Exception can be used as a wildcard that catches (almost) everything. However, it is good practice to be as specific as possible with the types of exceptions that we intend to handle, and to allow any unexpected exceptions to propagate on.

The most common pattern for handling Exception is to print or log the exception and then re-raise it (allowing a caller to handle the exception as well):

The try … except statement has an optional else clause, which, when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception. For example:

The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try … except statement.

Exception handlers do not handle only exceptions that occur immediately in the try clause, but also those that occur inside functions that are called (even indirectly) in the try clause. For example:

8.4. Raising Exceptions¶

The raise statement allows the programmer to force a specified exception to occur. For example:

The sole argument to raise indicates the exception to be raised. This must be either an exception instance or an exception class (a class that derives from BaseException , such as Exception or one of its subclasses). If an exception class is passed, it will be implicitly instantiated by calling its constructor with no arguments:

If you need to determine whether an exception was raised but don’t intend to handle it, a simpler form of the raise statement allows you to re-raise the exception:

8.5. Exception Chaining¶

If an unhandled exception occurs inside an except section, it will have the exception being handled attached to it and included in the error message:

To indicate that an exception is a direct consequence of another, the raise statement allows an optional from clause:

This can be useful when you are transforming exceptions. For example:

It also allows disabling automatic exception chaining using the from None idiom:

For more information about chaining mechanics, see Built-in Exceptions .

8.6. User-defined Exceptions¶

Programs may name their own exceptions by creating a new exception class (see Classes for more about Python classes). Exceptions should typically be derived from the Exception class, either directly or indirectly.

Exception classes can be defined which do anything any other class can do, but are usually kept simple, often only offering a number of attributes that allow information about the error to be extracted by handlers for the exception.

Most exceptions are defined with names that end in “Error”, similar to the naming of the standard exceptions.

Many standard modules define their own exceptions to report errors that may occur in functions they define.

8.7. Defining Clean-up Actions¶

The try statement has another optional clause which is intended to define clean-up actions that must be executed under all circumstances. For example:

If a finally clause is present, the finally clause will execute as the last task before the try statement completes. The finally clause runs whether or not the try statement produces an exception. The following points discuss more complex cases when an exception occurs:

If an exception occurs during execution of the try clause, the exception may be handled by an except clause. If the exception is not handled by an except clause, the exception is re-raised after the finally clause has been executed.

An exception could occur during execution of an except or else clause. Again, the exception is re-raised after the finally clause has been executed.

If the finally clause executes a break , continue or return statement, exceptions are not re-raised.

If the try statement reaches a break , continue or return statement, the finally clause will execute just prior to the break , continue or return statement’s execution.

If a finally clause includes a return statement, the returned value will be the one from the finally clause’s return statement, not the value from the try clause’s return statement.

A more complicated example:

As you can see, the finally clause is executed in any event. The TypeError raised by dividing two strings is not handled by the except clause and therefore re-raised after the finally clause has been executed.

In real world applications, the finally clause is useful for releasing external resources (such as files or network connections), regardless of whether the use of the resource was successful.

8.8. Predefined Clean-up Actions¶

Some objects define standard clean-up actions to be undertaken when the object is no longer needed, regardless of whether or not the operation using the object succeeded or failed. Look at the following example, which tries to open a file and print its contents to the screen.

The problem with this code is that it leaves the file open for an indeterminate amount of time after this part of the code has finished executing. This is not an issue in simple scripts, but can be a problem for larger applications. The with statement allows objects like files to be used in a way that ensures they are always cleaned up promptly and correctly.

After the statement is executed, the file f is always closed, even if a problem was encountered while processing the lines. Objects which, like files, provide predefined clean-up actions will indicate this in their documentation.

8.9. Raising and Handling Multiple Unrelated Exceptions¶

There are situations where it is necessary to report several exceptions that have occurred. This is often the case in concurrency frameworks, when several tasks may have failed in parallel, but there are also other use cases where it is desirable to continue execution and collect multiple errors rather than raise the first exception.

The builtin ExceptionGroup wraps a list of exception instances so that they can be raised together. It is an exception itself, so it can be caught like any other exception.

By using except* instead of except , we can selectively handle only the exceptions in the group that match a certain type. In the following example, which shows a nested exception group, each except* clause extracts from the group exceptions of a certain type while letting all other exceptions propagate to other clauses and eventually to be reraised.

Note that the exceptions nested in an exception group must be instances, not types. This is because in practice the exceptions would typically be ones that have already been raised and caught by the program, along the following pattern:

Читайте также:  Почему принтер выдает error

8.10. Enriching Exceptions with Notes¶

When an exception is created in order to be raised, it is usually initialized with information that describes the error that has occurred. There are cases where it is useful to add information after the exception was caught. For this purpose, exceptions have a method add_note(note) that accepts a string and adds it to the exception’s notes list. The standard traceback rendering includes all notes, in the order they were added, after the exception.

For example, when collecting exceptions into an exception group, we may want to add context information for the individual errors. In the following each exception in the group has a note indicating when this error has occurred.


Python Files and Exceptions

Working with files makes your programs more relevant and usable, also it makes your programs quickly analyze lots of data.

Learning to work with files and save data will make your programs easier for people to use. Users will be able to choose what data to enter and when to enter it. People can run your program, do some work, and then close the program and pick up where they left off later. Learning to handle exceptions will help you deal with situations in which files don’t exist and deal with other problems that can cause your programs to crash. This will make your programs more robust when they encounter bad data, whether it comes from innocent mistakes or from malicious attempts to break your programs. With these skills, you’ll make your programs more applicable, usable, and stable.

Reading from a File

An incredible amount of data is available in text files. Text files can contain weather data, traffic data, socioeconomic data, literary works, and more. Reading from a file is particularly useful in data analysis applications, but it’s also applicable to any situation in which you want to analyze or modify information stored in a file. For example, you can write a program that reads in the contents of a text file and rewrites the file with formatting that allows a browser to display it.

When you want to work with the information in a text file, the first step is to read the file into memory. You can read the entire contents of a file, or you can work through the file one line at a time.

Reading an Entire File

To begin, we need a file with a few lines of text in it. Let’s start with a file that contains pi to 30 decimal places, with 10 decimal places per line, consider we have a text file (pi_digits. txt) in the same directory of your program:

Exit fullscreen mode

Here’s a program that opens this file, reads it, and prints the contents of the file to the screen:

Exit fullscreen mode

The first line of this program with open(‘pi_digits.txt’) as file_object: has a lot going on. Let’s start by looking at the open() function. To do any work with a file, even just printing its contents, you first need to open the file to access it. The open() function needs one argument: the name of the file you want to open. Python looks for this file in the directory where the program that’s currently being executed is stored.

Here, open(‘pi_digits.txt’) returns an object representing pi_digits.txt. Python assigns this object to file_object, which we’ll work with later in the program.

The keyword with closes the file once access to it is no longer needed. Notice how we call open() in this program but not close(). You could open and close the file by calling open() and close(), but if a bug in your program prevents the close() method from being executed, the file may never close. This may seem trivial, but improperly closed files can cause data to be lost or corrupted. And if you call close() too early in your program, you’ll find yourself trying to work with a closed file (a file you can’t access), which leads to more errors. It’s not always easy to know exactly when you should close a file, but with the structure shown here, Python will figure that out for you. All you have to do is open the file and work with it as desired, trusting that Python will close it automatically when the with block finishes execution.

Once we have a file object representing pi_digits.txt, we use the read() method in the second line of our program contents = to read the entire contents of the file and store it as one long string in contents. When we print the value of contents, we get the entire text file back.

If you find a blank line appears at the end of your output that’s because read() returns an empty string when it reaches the end of the file; this empty string shows up as a blank line. If you want to remove the extra blank line, you can use rstrip() in the call to print().

Exit fullscreen mode

File Paths

When you pass a simple filename like pi_digits.txt to the open() function, Python looks in the directory where the file that’s currently being executed (that is, your . py program file) is stored.

Sometimes, depending on how you organize your work, the file you want to open won’t be in the same directory as your program file. For example, you might store your program files in a folder called python_work; inside python_work, you might have another folder called text_files to distinguish your program files from the text files they’re manipulating. Even though text_files is in python_work, just passing open()*the name of a file in *text_files won’t work, because Python will only look in python_work and stop there; it won’t go on and look in text_files.

To get Python to open files from a directory other than the one where your program file is stored, you need to provide a file path, which tells Python to look in a specific location on your system.

Because text_files is inside python_work, you could use a relative file path to open a file from text_files. A relative file path tells Python to look for a given location relative to the directory where the currently running program file is stored. For example, you’d write:

Exit fullscreen mode

This line tells Python to look for the desired . txt file in the folder text_files and assumes that text_files is located inside python_work.

Please note that, Windows systems use a backslash ( \ ) instead of a forward slash ( / ) when displaying file paths, but you can still use forward slashes in your code.

You can also tell Python exactly where the file is on your computer regardless of where the program that’s being executed is stored. This is called an absolute file path. You use an absolute path if a relative path doesn’t work. For instance, if you’ve put text_files in some folder other than python_work—say, a folder called other_files—then just passing open() the path ‘text_files/filename.txt’ won’t work because Python will only look for that location inside python_work. You’ll need to write out a full path to clarify where you want Python to look.

Absolute paths are usually longer than relative paths, so it’s helpful to assign them to a variable and then pass that variable to open():

Exit fullscreen mode

Using absolute paths, you can read files from any location on your system. For now it’s easiest to store files in the same directory as your program files or in a folder such as text_files within the directory that stores your program files.

Please note that, if you try to use backslashes in a file path, you’ll get an error because the backslash is used to escape characters in strings. For example, in the path C:\path\to\file.txt , the sequence \t is interpreted as a tab. If you need to use backslashes, you can escape each one in the path, like this: C:\\path\\to\\file.txt .

Reading Line by Line

When you’re reading a file, you’ll often want to examine each line of the file. You might be looking for certain information in the file, or you might want to modify the text in the file in some way. For example, you might want to read through a file of weather data and work with any line that includes the word sunny in the description of that day’s weather. In a news report, you might look for any line with the tag and rewrite that line with a specific kind of formatting.

You can use a for loop on the file object to examine each line from a file one at a time:

Exit fullscreen mode

Exit fullscreen mode

At file_name = ‘pi_digits.txt’ we assign the name of the file we’re reading from to the variable filename. This is a common convention when working with files. Because the variable filename doesn’t represent the actual file—it’s just a string telling Python where to find the file—you can easily swap out ‘pi_digits. txt’ for the name of another file you want to work with.

After we call open(), an object representing the file and its contents is assigned to the variable
file_object. We again use the with syntax to let Python open and close the file properly. To examine the file’s contents, we work through each line in the file by looping over the file object.

When we print each line, we find even more blank lines. These blank lines appear because an invisible newline character is at the end of each line in the text file. The print function adds its own newline each time we call it, so we end up with two newline characters at the end of each line: one from the file and one from print(). Using rstrip() on each line in the print() call eliminates these extra blank lines.

Exit fullscreen mode

Exit fullscreen mode

Making a List of Lines from a File

When you use with, the file object returned by open() is only available inside the with block that contains it. If you want to retain access to a file’s contents outside the with block, you can store the file’s lines in a list inside the block and then work with that list. You can process parts of the file immediately and postpone some processing for later in the program.

The following example stores the lines of pi_digits. txt in a list inside the with block and then prints the lines outside the with block:

Exit fullscreen mode

Exit fullscreen mode

At lines = object_file.readlines() the readlines() method takes each line from the file and stores it in a list. This list is then assigned to lines, which we can continue to work with after the with block ends.

At for line in lines: we use a simple for loop to print each line from lines. Because each item in lines corresponds to each line in the file, the output matches the contents of the file exactly.

Working with a File’s Contents

After you’ve read a file into memory, you can do whatever you want with that data, so let’s briefly explore the digits of pi. First, we’ll attempt to build a single string containing all the digits in the file with no whitespace in it:

Exit fullscreen mode

Exit fullscreen mode

We start by opening the file and storing each line of digits in a list, just as we did in the previous example. At pi_string = » we create a variable, pi_string, to hold the digits of pi. We then create a loop that adds each line of digits to pi_string and removes the newline character from each line pi_string += line.rstrip() .

Читайте также:  Postgresql logical replication error duplicate key value violates unique constraint

The variable pi_string contains the whitespace that was on the left side of the digits in each line, but we can get rid of that by using strip() instead of rstrip():

Exit fullscreen mode

Exit fullscreen mode

Now we have a string containing pi to 30 decimal places. The string is 32 characters long because it also includes the leading 3 and a decimal point.

Please note that, When Python reads from a text file, it interprets all text in the file as a string. If you read in a number and want to work with that value in a numerical context, you’ll have to convert it to an integer using the int() function or convert it to a float using the float() function.

Large Files: One Million Digits

So far we’ve focused on analyzing a text file that contains only three lines, but the code in these examples would work just as well on much larger files. If we start with a text file that contains pi to 1,000,000 decimal places instead of just 30, we can create a single string containing all these digits. We don’t need to change our program at all except to pass it a different file. We’ll also print just the first 50 decimal places, so we don’t have to watch a million digits scroll by in the terminal:

Exit fullscreen mode

Exit fullscreen mode

The output shows that we do indeed have a string containing pi to 1,000,000 decimal places.

Python has no inherent limit to how much data you can work with; you can work with as much data as your system’s memory can handle.

Is Your Birthday Contained in Pi?

Let’s use the program we just wrote to find out if someone’s birthday appears anywhere in the first million digits of pi. We can do this by expressing each birthday as a string of digits and seeing if that string appears anywhere in pi_string:

Exit fullscreen mode

Once you’ve read from a file, you can analyze its contents in just about any way you can imagine.

Writing to a File

One of the simplest ways to save data is to write it to a file. When you write text to a file, the output will still be available after you close the terminal containing your program’s output. You can examine output after a program finishes running, and you can share the output files with others as well. You can also write programs that read the text back into memory and work with it again later.

Writing to an Empty File

To write text to a file, you need to call open() with a second argument telling Python that you want to write to the file. To see how this works, let’s write a simple message and store it in a file instead of printing it to the screen:

Exit fullscreen mode

The call to open() in this example has two arguments. The first argument is still the name of the file we want to open. The second argument, ‘w’, tells Python that we want to open the file in write mode.

You can open a file in:

  • read mode (‘r’)
  • write mode (‘w’)
  • append mode (‘a’)
  • a mode that allows you to read and write to the file (‘r+’)

If you omit the mode argument, Python opens the file in read-only mode by default.

The open() function automatically creates the file you’re writing to if it doesn’t already exist. However, be careful opening a file in write mode (‘w’) because if the file does exist, Python will erase the contents of the file before returning the file object.

At file_object.write(«I Love Programming.») we use the write() method on the file object to write a string to the file. This program has no terminal output, but if you open the file (programming. txt), you’ll see one line.

Exit fullscreen mode

This file behaves like any other file on your computer. You can open it, write new text in it, copy from it, paste to it, and so forth.

Python can only write strings to a text file. If you want to store numerical data in a text file, you’ll have to convert the data to string format first using the str() function.

Writing Multiple Lines

The write() function doesn’t add any newlines to the text you write. So if you write more than one line without including newline characters, your file may not look the way you want it to:

Exit fullscreen mode

If you open (programming. txt), you’ll see the two lines squished together:

Exit fullscreen mode

Including newlines in your calls to write() makes each string appear on its own line:

Exit fullscreen mode

Exit fullscreen mode

You can also use spaces, tab characters, and blank lines to format your output, just as you’ve been doing with terminal-based output.

Appending to a File

If you want to add content to a file instead of writing over existing content, you can open the file in append mode. When you open a file in append mode, Python doesn’t erase the contents of the file before returning the file object. Any lines you write to the file will be added at the end of the file. If the file doesn’t exist yet, Python will create an empty file for you.

Let’s modify last program by adding some new reasons we love programming to the existing file (programming. txt):

Exit fullscreen mode

At with open(filename, ‘a’) as file_object: we use the ‘a’ argument to open the file for appending rather
than writing over the existing file. Then we write two new lines, which are added to (programming. txt).

Exit fullscreen mode

We end up with the original contents of the file, followed by the new content we just added.


Python uses special objects called exceptions to manage errors that arise during a program’s execution. Whenever an error occurs that makes Python unsure what to do next, it creates an exception object. If you write code that handles the exception, the program will continue running. If you don’t handle the exception, the program will halt and show a traceback, which includes a report of the exception that was raised.

Exceptions are handled with try-except blocks. A try-except block asks Python to do something, but it also tells Python what to do if an exception is raised. When you use try-except blocks, your programs will continue running even if things start to go wrong. Instead of tracebacks, which can be confusing for users to read, users will see friendly error messages that you write.

Handling the ZeroDivisionError Exception

Let’s look at a simple error that causes Python to raise an exception. You probably know that it’s impossible to divide a number by zero, but let’s ask Python to do it anyway:

Exit fullscreen mode

Exit fullscreen mode

Of course Python can’t do this, so we get a traceback. The error reported in the traceback ZeroDivisionError, is an exception object. Python creates this kind of object in response to a situation where it can’t do what we ask it to. When this happens, Python stops the program and tells us the kind of exception that was raised. We can use this information to modify our program. We’ll tell Python what to do when this kind of exception occurs; that way, if it happens again, we’re prepared.

Using try-except Blocks

When you think an error may occur, you can write a try-except block to handle the exception that might be raised. You tell Python to try running some code, and you tell it what to do if the code results in a particular kind of exception.

Here’s what a try-except block for handling the ZeroDivisionError exception looks like:

Exit fullscreen mode

We put print(5/0) , the line that caused the error, inside a try block. If the code in a try block works, Python skips over the except block. If the code in the try block causes an error, Python looks for an except block whose error matches the one that was raised and runs the code in that block.

In this example, the code in the try block produces a ZeroDivisionError, so Python looks for an except block telling it how to respond. Python then runs the code in that block, and the user sees a friendly error message instead of a traceback:

Exit fullscreen mode

If more code followed the try-except block, the program would continue running because we told Python how to handle the error. Let’s look at an example where catching an error can allow a program to continue running.

Using Exceptions to Prevent Crashes

Handling errors correctly is especially important when the program has more work to do after the error occurs. This happens often in programs that prompt users for input. If the program responds to invalid input appropriately, it can prompt for more valid input instead of crashing.

Let’s create a simple calculator that does only division:

Exit fullscreen mode

This program prompts the user to input a first_number and, if the user does not enter ‘q’ to quit, a second_number. We then divide these two numbers to get an answer w. This program does nothing to handle errors, so asking it to divide by zero causes it to crash:

Exit fullscreen mode

It’s bad that the program crashed, but it’s also not a good idea to let users see tracebacks. Nontechnical users will be confused by them, and in a malicious setting, attackers will learn more than you want them to know from a traceback. For example, they’ll know the name of your program file, and they’ll see a part of your code that isn’t working properly. A skilled attacker can sometimes use this information to determine which kind of attacks to use against your code.

The else Block

We can make this program more error resistant by wrapping the line that might produce errors in a try-except block. The error occurs on the line that performs the division, so that’s where we’ll put the try-except block. This example also includes an else block. Any code that depends on the try block executing successfully goes in the else block:

Exit fullscreen mode

Exit fullscreen mode

We ask Python to try to complete the division operation in a try block, which includes only the code that might cause an error. Any code that depends on the try block succeeding is added to the else block. In this case if the division operation is successful, we use the else block to print the result.

The except block tells Python how to respond when a ZeroDivisionError arises. If the try block doesn’t succeed because of a division by zero error, we print a friendly message telling the user how to avoid this kind of error. The program continues to run, and the user never sees a traceback.

The try-except-else block works like this: Python attempts to run the code in the try block. The only code that should go in a try block is code that might cause an exception to be raised. Sometimes you’ll have additional code that should run only if the try block was successful; this code goes in the else block. The except block tells Python what to do in case a certain exception arises when it tries to run the code in the try block.

By anticipating likely sources of errors, you can write robust programs that continue to run even when they encounter invalid data and missing resources. Your code will be resistant to innocent user mistakes and malicious attacks.

Читайте также:  Что это debugger exception notification

Handling the FileNotFoundError Exception

One common issue when working with files is handling missing files. The file you’re looking for might be in a different location, the filename may be misspelled, or the file may not exist at all. You can handle all of these situations in a straightforward way with a try-except block.

Let’s try to read a file that doesn’t exist. The following program tries to read in the contents of A*lice in Wonderland*, but we haven’t saved the file (alice. txt) in the same directory as (alice. py):

Exit fullscreen mode

There are two changes here. One is the use of the variable f to represent the file object, which is a common convention. The second is the use of the encoding argument. This argument is needed when your system’s default encoding doesn’t match the encoding of the file that’s being read.

Python can’t read from a missing file, so it raises an exception:

Exit fullscreen mode

The last line of the traceback reports a FileNotFoundError: this is the exception Python creates when it can’t find the file it’s trying to open.

In this example, the open() function produces the error, so to handle it, the try block will begin with the line that contains open():

Exit fullscreen mode

In this example, the code in the try block produces a FileNotFoundError, so Python looks for an except block that matches that error. Python then runs the code in that block, and the result is a friendly error message instead of a traceback:

Exit fullscreen mode

The program has nothing more to do if the file doesn’t exist, so the error-handling code doesn’t add much to this program. Let’s build on this example and see how exception handling can help when you’re working with more than one file.

Analyzing Text

You can analyze text files containing entire books. Many classic works of literature are available as simple text files because they are in the public domain. The texts used in this section come from Project Gutenberg ( Project Gutenberg maintains a collection of literary works that are available in the public domain, and it’s a great resource if you’re interested in working with literary texts in your programming projects.

Let’s pull in the text of Alice in Wonderland and try to count the number of words in the text. We’ll use the string method split(), which can build a list of words from a string. Here’s what split() does with a string containing just the title «Alice in Wonderland»:

Exit fullscreen mode

The split() method separates a string into parts wherever it finds a space and stores all the parts of the string in a list. The result is a list of words from the string, although some punctuation may also appear with some of the words. To count the number of words in Alice in Wonderland, we’ll use split() on the entire text. Then we’ll count the items in the list to get a rough idea of the number of words in the text:

Exit fullscreen mode

Move the file (alice. txt) to the correct directory, so the try block will work this time. At words = contents.split() we take the string contents, which now contains the entire text of Alice in Wonderland as one long string, and use the split() method to produce a list of all the words in the book. When we use len() on this list to examine its length, we get a good approximation of the number of words in the original string num_words = len(words) .

Then we print a statement that reports how many words were found in the file. This code is placed in the else block because it will work only if the code in the try block was executed successfully. The output tells us how many words are in (alice. txt):

Exit fullscreen mode

The count is a little high because extra information is provided by the publisher in the text file used here, but it’s a good approximation of the length of Alice in Wonderland.

Working with Multiple Files

Let’s add more books to analyze. But before we do, let’s move the bulk of this program to a function called count_words(). By doing so, it will be easier to run the analysis for multiple books:

Exit fullscreen mode

Most of this code is unchanged. We simply indented it and moved it into the body of count_words(). It’s a good habit to keep comments up to date when you’re modifying a program, so we changed the comment to a docstring and reworded it slightly.

Now we can write a simple loop to count the words in any text we want to analyze. We do this by storing the names of the files we want to analyze in a list, and then we call count_words() for each file in the list.

Exit fullscreen mode

Exit fullscreen mode

The siddhartha. txt file is missed from the directory but it has no effect on the rest of the program’s execution.

Using the try-except block in this example provides two significant advantages:

  • We prevent our users from seeing a traceback.
  • we let the program continue analyzing the texts it’s able to find.

If we don’t catch the FileNotFoundError that ‘siddhartha. txt’ raised, the user would see a full traceback, and the program would stop running after trying to analyze Siddhartha. It would never analyze Moby Dick or Little Women.

Failing Silently

In the previous example, we informed our users that one of the files was unavailable. But you don’t need to report every exception you catch. Sometimes you’ll want the program to fail silently when an exception occurs and continue on as if nothing happened. To make a program fail silently, you write a try block as usual, but you explicitly tell Python to do nothing in the except block. Python has a pass statement that tells it to do nothing in a block:

Exit fullscreen mode

The only difference between this listing and the previous one is the pass statement. Now when a FileNotFoundError is raised, the code in the except block runs, but nothing happens. No traceback is produced, and there’s no output in response to the error that was raised. Users see the word counts for each file that exists, but they don’t see any indication that a file wasn’t found.

Exit fullscreen mode

The pass statement also acts as a placeholder. It’s a reminder that you’re choosing to do nothing at a specific point in your program’s execution and that you might want to do something there later. For example, in this program we might decide to write any missing filenames to a file called (missing_files. txt). Our users wouldn’t see this file, but we’d be able to read the file and deal with any missing texts.

Deciding Which Errors to Report

How do you know when to report an error to your users and when to fail silently? If users know which texts are supposed to be analyzed, they might appreciate a message informing them why some texts were not analyzed. If users expect to see some results but don’t know which books are supposed to be analyzed, they might not need to know that some texts were unavailable. Giving users information they aren’t looking for can decrease the usability of your program. Python’s error-handling structures give you fine-grained control over how much to share with users when things go wrong; it’s up to you to decide how much information to share.

Well-written, properly tested code is not very prone to internal errors, such as syntax or logical errors. But every time your program depends on something external, such as user input, the existence of a file, or the availability of a network connection, there is a possibility of an exception being raised. A little experience will help you know where to include exception handling blocks in your program and how much to report to users about errors that arise.

Storing Data

Many of your programs will ask users to input certain kinds of information. You might allow users to store preferences in a game or provide data for a visualization. Whatever the focus of your program is, you’ll store the information users provide in data structures such as lists and dictionaries. When users close a program, you’ll almost always want to save the information they entered. A simple way to do this involves storing your data using the json module.

The json module allows you to dump simple Python data structures into a file and load the data from that file the next time the program runs. You can also use json to share data between different Python programs. Even better, the JSON data format is not specific to Python, so you can share data you store in the JSON format with people who work in many other programming languages. It’s a useful and portable format, and it’s easy to learn.

The **JSON* (JavaScript Object Notation) format was originally developed for JavaScript. However, it has since become a common format used by many languages, including Python.*

Using json.dump() and json.load()

Let’s write a short program that stores a set of numbers and another program that reads these numbers back into memory. The first program will use json.dump() to store the set of numbers, and the second program will use json.load() .

The json.dump() function takes two arguments: a piece of data to store and a file object it can use to store the data. Here’s how you can use json.dump() to store a list of numbers:

Exit fullscreen mode

We first import the json module and then create a list of numbers to work with. At filename = ‘numbers.json’ we choose a filename in which to store the list of numbers. It’s customary to use the file extension .json to indicate that the data in the file is stored in the JSON format. Then we open the file in write mode, which allows json to write the data to the file. At json.dump(numbers, f) we use the json.dump() function to store the list numbers in the file (numbers. json).

This program has no output, but let’s open the file (numbers. json) and look at it. The data is stored in a format that looks just like Python:

Exit fullscreen mode

Now we’ll write a program that uses json.load() to read the list back into memory:

Exit fullscreen mode

Exit fullscreen mode

At filename = ‘numbers.json’ we make sure to read from the same file we wrote to. This time when we open the file, we open it in read mode because Python only needs to read from the file. At numbers = json.load(f) we use the json.load() function to load the information stored in (numbers. json), and we assign it to the variable numbers. Finally we print the recovered list of numbers and see that it’s the same list created before.

This is a simple way to share data between two programs.

Saving and Reading User-Generated Data

Saving data with json is useful when you’re working with user-generated data, because if you don’t store your user’s information somehow, you’ll lose it when the program stops running. Let’s look at an example where we prompt the user for their name the first time they run a program and then remember their name when they run the program again.

Let’s start by storing the user’s name:


Оцените статью