Context manager: Difference between revisions

From Helpful
Jump to navigation Jump to search
mNo edit summary
mNo edit summary
(4 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{#addbodyclass:tag_tech}}
{{#addbodyclass:tag_prog}}


{{programming}}


Context managers bolt hook in some implied extra code, onto a code blocks, via syntactic sugar.
Context managers are syntactic sugar you use on a code block, to bolt in some implied extra code.




 
They seem largely used to do resource cleanup more implicitly and automatically,
Often used to do some resource cleanup more implicitly and automatically, but there are various other uses.  
but there are various other uses.  


<!--
<!--
Line 36: Line 39:




At its core, the {{inlinecode|with}} statement takes an object; that object's its
At its core, the {{inlinecode|with}} statement takes an object; that object's has a
* __enter__() will be called at the start of the block
* __enter__() that will be called at the start of the block
: and returns the thing that will be assigned
: and returns the thing that will be assigned


* __exit__() will be called afterwards
* __exit__() that will be called afterwards
: also if an exception is raised (so is much like a  try-finally)
: also if an exception is raised (so is much like a  try-finally)


Line 65: Line 68:
         self.fob.close()
         self.fob.close()


# Prove to yourself that it works:
with Test('textfile') as t:
with Test('textfile') as t:
     print( t )
     print( t )
Line 70: Line 74:




You may prefer to use the @contextlib.contextmanager decorator, which is mild trickery where you write a generator,
 
everything before the yield is effectively run as part of __enter__, and that exactly-one yield is what gets assigned
Another way to write something like that is @contextlib.contextmanager decorator.
 
This is '''further''' trickery where you write a generator,  
everything before the yield is effectively run as part of __enter__, and that exactly-one yield is what gets assigned.


<syntaxhighlight lang="python">
<syntaxhighlight lang="python">
Line 85: Line 92:
     print( t )
     print( t )
</syntaxhighlight>
</syntaxhighlight>
Notes:
* there is also a way to ease creating a [[mixin]]


==Javascript==
==Javascript==

Revision as of 23:07, 20 April 2024

Some fragmented programming-related notes, not meant as introduction or tutorial

Data: Numbers in computers ·· Computer dates and times ·· Data structures

Wider abstractions: Programming language typology and glossary · Generics and templating ·· Some abstractions around programming · · Computational complexity theory notes · Synchronous, asynchronous · First-class citizen

Syntaxy abstractions: Constness · Memory aliasing · Binding, assignment, and such · Closures · Context manager · Garbage collection

Sharing stuff: Communicated state and calls · Locking, data versioning, concurrency, and larger-scale computing notes

Language specific: Python notes ·· C and C++ notes · Compiling and linking ·· Lua notes

Teams and products: Programming in teams, working on larger systems, keeping code healthy · Benchmarking, performance testing, load testing, stress testing, etc. · Maintainability

More applied notes: Optimized number crunching · File polling, event notification · Webdev · GUI toolkit notes

Mechanics of duct taping software together: Automation, remote management, configuration management · Build tool notes · Installers


Context managers are syntactic sugar you use on a code block, to bolt in some implied extra code.


They seem largely used to do resource cleanup more implicitly and automatically, but there are various other uses.



Python

This article/section is a stub — some half-sorted notes, not necessarily checked, not necessarily correct. Feel free to ignore, or tell me about it.


For example:

with open(filename) as file:
   file_data = file.read()

is roughly equivalent to

try:
   file = open(filename)
   file_data = file.read()
finally:
   file.close()

...because the built-in open() already implements the interface we're about to describe (and e.g. does a close in its __exit__).


At its core, the with statement takes an object; that object's has a

  • __enter__() that will be called at the start of the block
and returns the thing that will be assigned
  • __exit__() that will be called afterwards
also if an exception is raised (so is much like a try-finally)



If open() were unaware of this interface, we might add it like in the following example (as it is, this example is redundant and pointless. A better example would be a database connection, but it'd take a few more lines to actually be runnable code)

You can write this more manually like:

class Test(object):
    def __init__(self, filename):  # __init__ isn't part of concept, but is how you get parameters in 
        self.filename = filename   #  (without which you'll find it hard to get __enter__ to return something useful to you)

    def __enter__(self):
        print('__enter__')
        self.fob = open(self.filename)
        return self.fob

    def __exit__(self, exc_type,exc_value, exc_traceback):
        print('__exit__')
        self.fob.close()

# Prove to yourself that it works:
with Test('textfile') as t:
    print( t )


Another way to write something like that is @contextlib.contextmanager decorator.

This is further trickery where you write a generator, everything before the yield is effectively run as part of __enter__, and that exactly-one yield is what gets assigned.

@contextlib.contextmanager
def test(filename): # 
    f = open(filename)
    try:
        yield f
    finally:
        f.close()

with test('textfile') as t:
    print( t )

Javascript

This article/section is a stub — some half-sorted notes, not necessarily checked, not necessarily correct. Feel free to ignore, or tell me about it.

Nothing built in, but because ES6 has generators(good support since ~2017) you can insert both some before and after code, much like that second python example.

To copy-paste from [1]:

function* usingGroup() {
   console.group()
   try {
     yield;
   } finally {
     console.groupEnd();
   }
}

for(const _ of usingGroup()) {
   console.log('inside a group')
}

The same page also mentions a library to make this a little easier, imitating python.

C#

This article/section is a stub — some half-sorted notes, not necessarily checked, not necessarily correct. Feel free to ignore, or tell me about it.