diff --git a/examples/stdout.py b/examples/stdout.py new file mode 100644 index 0000000..0df4432 --- /dev/null +++ b/examples/stdout.py @@ -0,0 +1,17 @@ +import sys + +class RedirectStdoutTo: + def __init__(self, out_new): + self.out_new = out_new + + def __enter__(self): + self.out_old = sys.stdout + sys.stdout = self.out_new + + def __exit__(self, *args): + sys.stdout = self.out_old + +print('A') +with open('out.log', mode='w', encoding='utf-8') as a_file, RedirectStdoutTo(a_file): + print('B') +print('C') diff --git a/files.html b/files.html index f4e2ff5..318fd04 100644 --- a/files.html +++ b/files.html @@ -126,7 +126,7 @@ UnicodeDecodeError: 'charmap' codec can't decode byte 0x8f in position 28: chara
Let’s see that again. +
Let’s try that again.
# continued from the previous example @@ -142,7 +142,7 @@ UnicodeDecodeError: 'charmap' codec can't decode byte 0x8f in position 28: chara
Do you see it yet? The seek() and tell() methods always count bytes, but since you opened this file as text, the read() method counts characters. Chinese characters require multiple bytes to encode in UTF-8. The English characters in the file only require one byte each, so you might be misled into thinking that they’re counting the same thing. But that’s only true for some characters.
+
Do you see it yet? The seek() and tell() methods always count bytes, but since you opened this file as text, the read() method counts characters. Chinese characters require multiple bytes to encode in UTF-8. The English characters in the file only require one byte each, so you might be misled into thinking that the seek() and read() methods are counting the same thing. But that’s only true for some characters.
But wait, it gets worse! @@ -217,9 +217,11 @@ ValueError: I/O operation on closed file.
Here’s the kicker: no matter how or when you exit the with block, Python will close that file… even if you “exit” it via an unhandled exception. That’s right, even if your code raises an exception and your entire program comes to a screeching halt, that file will get closed. Guaranteed.
-+☞The
withstatement is not limited to standard file objects. You can also use it with compressed file objects fromgzip.GzipFileandbz2.BZ2File(example). Nor is it limited to files; you can use it in unit testing to test that certain exceptions are raised when expected (example). +☞In technical terms, the
withstatement creates a runtime context. In these examples, the file object acts as a context manager. Python creates the file object a_file and tells it that it is entering a runtime context. When thewithcode block is completed, Python tells the file object that it is exiting the runtime context, and the file object calls its ownclose()method. See Appendix B, “Context Managers” for details.
There’s nothing file-specific about the with statement; it’s just a generic framework for creating runtime contexts and telling objects that they’re entering and exiting a runtime context. If the object in question is a file object, then it does useful file-like things (like closing the file automatically). But that behavior is defined in the file object, not in the with statement. There are lots of other ways to use context managers that have nothing to do with files. You can even create your own, as you’ll see later in this chapter.
+
A “line” of a text file is just what you think it is — you type a few words and press ENTER, and now you’re on a new line. A line of text is a sequence of characters delimited by… what exactly? Well, it’s complicated, because text files can use several different characters to mark the end of a line. Every operating system has its own convention. Some use a carriage return character, others use a line feed character, and some use both characters at the end of every line. @@ -306,8 +308,8 @@ ValueError: I/O operation on closed file.
Now you’ve seen enough to understand the file handling code in the fileinfo.py sample code from the previous chapter. This example shows how to safely open and read from a file and gracefully handle
errors.
MP3FileInfo
- try: ① fsock = open(filename, "rb", 0) ② try: fsock.seek(-128, 2) ③ tagdata = fsock.read(128) ④ finally: ⑤ fsock.close() . . .
- except IOError: ⑥ pass
+ try: ① fsock = open(filename, "rb", 0) ② try: fsock.seek(-128, 2) ③ tagdata = fsock.read(128) ④ finally: ⑤ fsock.close() . . .
+ except IOError: ⑥ pass
try...except block. (Hey, isn’t standardized indentation great? This is where you start to appreciate it.)
open function may raise an IOError. (Maybe the file doesn’t exist.)
@@ -387,113 +389,112 @@ b'\xff\xd8\xff'
FIXME +
Command-line gurus are already familiar with the concept of standard input, standard output, and standard error. This section is for the rest of you. - +
__init__() method is called immediately after an instance is created. It takes one parameter, the file-like object that you want to use as standard output for the life of the context. This method just saves the file-like object in an instance variable so other methods can use it later.
+__enter__() method is a special class method; Python calls it when entering a context (i.e. at the beginning of the with statement). This method saves the current value of sys.stdout in self.out_old, then redirects standard output by assigning self.out_new to sys.stdout.
+__exit__() method is another special class method; Python calls it when exiting the context (i.e. at the end of the with statement). This method restores standard output to its original value by assigning the saved self.out_old value to sys.stdout.
+Redirecting standard error works exactly the same way, using sys.stderr instead of sys.stdout.
FIXME - -
☜ ☞ diff --git a/special-method-names.html b/special-method-names.html index cec4b8d..b5eb365 100644 --- a/special-method-names.html +++ b/special-method-names.html @@ -759,6 +759,8 @@ def __exit__(self, *args):
☞The __exit__() method will always be called, even if an exception is raised inside the with block. In fact, if an exception is raises, the exception information will be passed to the __exit__() method. See With Statement Context Managers for more details.
+
For more on context managers, see Closing Files Automatically and Redirecting Standard Output. +
If you know what you’re doing, you can gain almost complete control over how classes are compared, how attributes are defined, and what kinds of classes are considered subclasses of your class.