I'm trying to write a context manager decorator using Python's contextlib.ContextDecorator class.
Is there a way to access the decorated function's parameters within the context manager?
Here's an example of what I'm doing:
from contextlib import ContextDecorator
class savePen(ContextDecorator):
def __enter__(self):
self.prevPen = self.dc.GetPen() # AttributeError
return self
def __exit__(self, *exc):
self.dc.SetPen(self.prevPen)
return False
Given the above, this:
@savePen()
def func(dc, param1, param2):
# do stuff, possibly changing the pen style
should be equivalent to:
def func(dc, param1, param2):
prevPen = dc.GetPen()
# do stuff, possibly changing the pen style
dc.SetPen(prevPen)
I've scoured the docs for contextlib and haven't found anything useful.
Does anyone know how to access the decorated functions' attributes from within a ContextDecorator class?
As @chepner said in this response, ContextDecorator is sugar for
def func(dc, param1, param2):
with savePen():
...
and that it cannot access the functions' parameters.
However, in this case, whatever runs inside of with savePen()
has access to the function parameters dc
, param1
, and param2
. This makes me think that I should be able to access them using ContextDecorator.
For example, this is valid:
def func(dc, param1, param2):
with savePen():
print(param1)
Choose the dot property accessor when the property name is known ahead of time. The dot property accessor works correctly when the property name is a valid identifier. An identifier in JavaScript contains Unicode letters, $, _, and digits 0..9, but cannot start with a digit.
3 Ways To Access Object Properties in JavaScript 1. Dot property accessor. You can use the dot property accessor in a chain to access deeper properties: object.prop1. 2. Square brackets property accessor. The first expression should evaluate to an object and the second expression should... 3. Object ...
The dot property accessor works correctly when the property name is a valid identifier. An identifier in JavaScript contains Unicode letters, $, _, and digits 0..9, but cannot start with a digit. This is not a problem, because usually, the property names are valid identifiers: e.g. name, address, street, createdBy.
contextlib.contextmanager
seems more appropriate here. Note that, like anything else, you can't access the local variables of a function body from outside the function (short of introspection hacks, anyway).
@contextlib.contextmanager
def savePen(dc):
prevPen = dc.GetPen()
yield
dc.SetPen(prevPen)
with savePen(dc):
func(dc, param1, param2)
Note that with a ContextDecorator
, the context manager is instantiated with no arguments, that is
@savePen()
def func(dc, param1, param2):
# do stuff, possibly changing the pen style
is syntactic sugar (according to the documentation) for
def func(dc, param1, param2):
with savePen():
...
and so there's no way to tell savePen
which object (dc
) to work with.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With