We haven't talked about __exit__ The three parameters of the method :type, value and traceback.
In the 4 And the first step 6 Between steps , If something unusual happens ,Python Will be abnormal type,value and traceback Pass to __exit__ Method .
It makes __exit__ Method to determine how to close the file and whether additional steps are required . In our case , We didn't notice them .
What if our file object throws an exception ? In case we try to access an unsupported method of a file object . for instance :
with File('demo.txt', 'w') as opened_file:
opened_file.undefined_function('Hola!')
Let's list , When an exception occurs ,with What steps will the statement take .
1. It puts the abnormal type,value and traceback Pass to __exit__ Method
2. It makes __exit__ Method to handle exceptions
3. If __exit__ The return is True, Then the exception is handled gracefully .
4. If __exit__ The return is True Anything other than , So this exception will be with Statement throw .
In our case ,__exit__ Method returns None( without return Statement, the method will return None). therefore ,with Statement threw that exception .
Traceback (most recent call last):File "<stdin>", line 2, in <module>
AttributeError: 'file' object has no attribute 'undefined_function'
Let's try at __exit__ Method :
class File(object):
def __init__(self, file_name, method):
self.file_obj = open(file_name, method)
def __enter__(self):
return self.file_obj
def __exit__(self, type, value, traceback):
print("Exception has been handled")
self.file_obj.close()
return True
with File('demo.txt', 'w') as opened_file:
opened_file.undefined_function()
# Output: Exception has been handled
our __exit__ Method returns True, So no exceptions will be with Statement throw .
This is not the only way to implement a context manager . There's another way , We'll look at it together in the next section .
We can also use decorators (decorators) And generators (generators) To implement the context manager .
Python There is one contextlib Modules are designed for this purpose . We can use a generator function to implement a context manager , Instead of using a class .
Let's look at a basic , Useless examples :
from contextlib import contextmanager
@contextmanager
def open_file(name):
f = open(name, 'w')
yield f
f.close()
OK La ! This implementation looks more intuitive and simple . However , This method requires information about the generator 、yield And some knowledge of decorators . In this example, we haven't caught any exceptions that may occur . It works in much the same way as before .
Let's dissect this method a little .
1. Python The interpreter encountered yield keyword . For this reason, it creates a generator instead of a normal function .
2. Because this decorator ,contextmanager Will be called and passed in the function name (open_file) As a parameter .
3. contextmanager The function returns a with GeneratorContextManager Object encapsulated generator .
4. This GeneratorContextManager Assigned to open_file function , We're actually calling GeneratorContextManager object .
Now that we know all this , We can use this newly generated context manager , like this :
with open_file('some_file') as f:
f.write('hola!')
thus ,Python Advanced has ended , Thank you for your support .