This issue tracker has been migrated to GitHub ,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2014年09月09日 20:58 by terry.reedy, last changed 2022年04月11日 14:58 by admin. This issue is now closed.
| Files | ||||
|---|---|---|---|---|
| File name | Uploaded | Description | Edit | |
| issue22374.diff | berker.peksag, 2016年06月02日 01:59 | review | ||
| Messages (6) | |||
|---|---|---|---|
| msg226661 - (view) | Author: Terry J. Reedy (terry.reedy) * (Python committer) | Date: 2014年09月09日 20:58 | |
https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager The current html contextmanager example is 'not recommended' for actual use, because there are better ways to accomplish the same goal. To me, is also unsatifactory in that the context management is only metaphorical (conceptual) and not actual. I propose the following as a replacement. It actually manages context and is, I believe, both useful and currently* the best way to accomplish the goal of temporarily monkeypatching a module, It was directly inspired by #20752, see msg226657, though there have been other issues where monkeypatching as a solution has been discussed. --- from contextlib import contextmanager import itertools as its @contextmanager def mp(ob, attr, new): old = getattr(ob, attr) setattr(ob, attr, new) yield setattr(ob, attr, old) def f(): pass print(its.count, its.cycle) with mp(its, 'count', f), mp(its, 'cycle', f): print(its.count, its.cycle) print(its.count, its.cycle) # <class 'itertools.count'> # <function f at 0x00000000035A91E0> # <class 'itertools.count'> --- I am aware that the above does not follow the current style, which I dislike, of confusingly mixing together batch file code and interactive input code. I think the above is how the example should be written. It would work even better if Sphinx gave comment lines a different background color. (A '##' prefix could be used to differentiate code comments from commented-out output lines.) In the same section, I find the following paragraph a bit confusing (perhaps is tries to say too much): "contextmanager() uses ContextDecorator so the context managers it creates can be used as decorators as well as in with statements. When used as a decorator, a new generator instance is implicitly created on each function call (this allows the otherwise "one-shot" context managers created by contextmanager() to meet the requirement that context managers support multiple invocations in order to be used as decorators)." I am guessing that this means, among other things, that ContextDecorator is necessary and sufficient to use mp twice in one with statement. I intentionally added the double use to the example to make this possibility clear. * The only better way I know of would be if mp (spelled out as 'monkeypatch' were considered useful enough to be added to contextlib. |
|||
| msg226686 - (view) | Author: Martin Panter (martin.panter) * (Python committer) | Date: 2014年09月10日 07:21 | |
You should probably use try / finally in your context manager to always restore the attribute. Having said that, I recently wrote a similar context manager, and then later discovered there is already "unittest.mock.patch" and/or "unittest.mock.patch.object" via Issue 11664, which apparently can do this job. |
|||
| msg266862 - (view) | Author: Berker Peksag (berker.peksag) * (Python committer) | Date: 2016年06月02日 01:59 | |
We also have swap_attr() and swap_item() helpers in Lib/test/support/__init__.py. I've used a simplified version of swap_attr() in my patch. Since this is basically a document improvement I removed Python 2.7 from the versions field. |
|||
| msg266918 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) | Date: 2016年06月02日 19:04 | |
swap_attr() looks too general. I think something more concrete would be better. But the documentation already contain other examples for contextmanager. closing() is good example, and redirect_stdout() would be good example. |
|||
| msg311203 - (view) | Author: cowlinator (cowlinator) | Date: 2018年01月30日 00:28 | |
I would like to second the improved explanation of contextlib.contextmanager, and additionally point out another problem: A very important piece of information is missing from the documentation: how to return data from the contextmanager-wrapped function. I had to go look up the source code, which had a wonderful explanation in the comments: https://gist.github.com/enuomi/1385336#file-contextlib-py-L56 In particular, note that @contextmanager def some_generator(<arguments>): yield <return_data> can be used to return <return_data> to the caller, via with some_generator(<arguments>) as <return_data>: print(return_data) This information is wholly and completely missing from the contextlib.contextmanager documentation. |
|||
| msg322397 - (view) | Author: Berker Peksag (berker.peksag) * (Python committer) | Date: 2018年07月26日 05:37 | |
The old tag() example has been replaced with a different example in https://github.com/python/cpython/commit/bde782bb594edffeabe978abeee2b7082ab9bc2a (bpo-33468) |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022年04月11日 14:58:07 | admin | set | github: 66568 |
| 2018年07月26日 05:37:12 | berker.peksag | set | status: open -> closed superseder: Add try-finally contextlib.contextmanager example messages: + msg322397 resolution: duplicate stage: patch review -> resolved |
| 2018年01月30日 00:28:19 | cowlinator | set | nosy:
+ cowlinator messages: + msg311203 versions: + Python 2.7, Python 3.4, Python 3.7 |
| 2016年06月02日 19:04:47 | serhiy.storchaka | set | nosy:
+ serhiy.storchaka messages: + msg266918 |
| 2016年06月02日 01:59:50 | berker.peksag | set | files:
+ issue22374.diff type: enhancement versions: + Python 3.6, - Python 2.7, Python 3.4 keywords: + patch nosy: + berker.peksag messages: + msg266862 stage: patch review |
| 2014年09月10日 07:21:53 | martin.panter | set | nosy:
+ martin.panter messages: + msg226686 |
| 2014年09月09日 20:58:12 | terry.reedy | create | |