-
Notifications
You must be signed in to change notification settings - Fork 5.9k
Adds context manager section to structure.rst #627
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -316,6 +316,75 @@ expensive function in a table and use them directly instead of recomputing | |
| them when they have already been computed. This is clearly not part | ||
| of the function logic. | ||
|
|
||
| Context Managers | ||
| ---------------- | ||
|
|
||
| A context manager is a Python object that provides extra contextual information | ||
| to an action. This extra information takes the form of running a function upon | ||
| initiating the context using the ``with`` statement as well as running a function | ||
| upon completing all the code inside the ``with`` block. The most well known | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you please update this to say |
||
| example of using a context manager is operating on a file: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| with open('file.txt') as f: | ||
| contents = f.read() | ||
|
|
||
| Anyone familiar with this pattern knows that invoking ``open`` in this fashion | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove "Anyone familiar with this pattern knows that". That alienates people who do not already know and those people are a target audience for this document. |
||
| ensures that ``f``'s ``close`` method will be called at some point. This reduces | ||
| a developer's cognitive load and makes code easier to read. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's reword this sentence to say: |
||
|
|
||
| There are two easy ways to implement this functionality yourself: using a class | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's remove "easy" from this sentence. It alienates new developers who are the target audience for this document. |
||
| or using a generator. Let's implement the above functionality ourselves, starting | ||
| with the class approach: | ||
|
|
||
| .. code-block:: python | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This example does not explain the parameters to the exit method. Either turn those into |
||
|
|
||
| class CustomOpen(object): | ||
| def __init__(self, filename): | ||
| self.file = open(filename) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not indented appropriately. |
||
|
|
||
| def __enter__(self): | ||
| return self.file | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This works but I do not believe it is a practice that we should encourage (returning something other than the object you're instantiating as the value in the context manager). I've never seen this pattern before. Can you point to projects using anything like this for an object? |
||
|
|
||
| def __exit__(self, ctx_type, ctx_value, ctx_traceback): | ||
| self.file.close() | ||
|
|
||
| with CustomOpen('file') as f: | ||
| contents = f.read() | ||
|
|
||
| This is just a regular Python object with two extra methods that are used | ||
| by the ``with`` statement. CustomOpen is first instantiated and then its | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You probably wanted double-backticks around "CustomOpen" |
||
| ``__enter__`` method is called and whatever ``__enter__`` returns is assigned to | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace "assigned" with "bound" |
||
| ``f`` in the ``as f`` part of the statement. When the contents of the ``with`` block | ||
| is finished executing, the ``__exit__`` method is then called. | ||
|
|
||
| And now the generator approach using Python's own | ||
| `contextlib <https://docs.python.org/2/library/contextlib.html>`_: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| from contextlib import contextmanager | ||
|
|
||
| @contextmanager | ||
| def custom_open(filename): | ||
| f = open(filename) | ||
| yield f | ||
| f.close() | ||
|
|
||
| with custom_open('file') as f: | ||
| contents = f.read() | ||
|
|
||
| This works in exactly the same way as the class example above, albeit it's | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace "albeit" with "but" |
||
| more terse. The ``custom_open`` function executes until it reaches the ``yield`` | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "terser" not "more terse" |
||
| statement. It then gives control back to the ``with`` statement, which assigns | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove "back" here please.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "assigns" -> "binds" |
||
| whatever was ``yield``'ed to `f` in the ``as f`` portion. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. whatever was returned by ``yield`` to ``f``.(Make sure the "f" has double backticks around it.) |
||
|
|
||
| Since the two approaches appear the same, we should follow the Zen of Python | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace with |
||
| to decide when to use which. The class approach might be better if there's | ||
| a considerable amount of logic to encapsulate. The function approach | ||
| might be better for situations where we're dealing with a simple action. | ||
|
|
||
| Dynamic typing | ||
| -------------- | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind adding "at runtime" after "to an action"/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not necessarily running functions (as you show with the second example you provided).