1
\$\begingroup\$

I wanted to ask this here because what I wanted to originally do felt like a really Pythonic method. I want to be able to use the syntax:

d = {'apple':{'cranberry':{'banana':{'chocolate':[1,2,3,4,5,6]}}},'b':2}
with d['apple']['cranberry']['banana']['chocolate'] as item:
    for i in item:
        print(i)

    item.append('k')

but found that Python doesn't allow for using lists, dicts, etc. as context managers.

So I implemented my own:

def context_wrap(target):
    class ContextWrap:
        def __init__(self, tgt):
            self._tgt = tgt

        def __enter__(self):
            return self._tgt

        def __exit__(self, type, value, traceback):
            pass

    return ContextWrap(target)

if __name__ == '__main__':
    with context_wrap({'a':1}) as item:
        print(item['a'])

    with context_wrap([1,2,3,4,5]) as item:
        print(item[1])

    with context_wrap(3) as item:
        print (item)

In the above code, you can take any random object and wrap it inside an object that acts as a context manager controlling the underlying object. This means that inside any with clause, you can simply use the object with it's alias. I feel like it looks a lot cleaner and clearer than something like:

alias = d['apple']['cranberry']['banana']['chocolate']
for i in alias:
    print(i)

alias.append('k')

I wanted to know if there was a more "Pythonic" way to do it. So the improvement that I'm looking for is in terms of better reliance on the standard Python library and/or in terms of my syntax.

\$\endgroup\$
5
  • 3
    \$\begingroup\$ What's the advantage of this over just saying item = d['a']? Usually the purpose of a context manager is to do something in the __exit__ (close a file, free a resource, etc) but your use case doesn't require anything like that. \$\endgroup\$ – Samwise Feb 26 '20 at 23:59
  • \$\begingroup\$ Welcome to code review, the question might be better received if the title was something like Context Manager Wrapper and there was a paragraph explaining what the code does. \$\endgroup\$ – pacmaninbw Feb 27 '20 at 0:23
  • 1
    \$\begingroup\$ @pacmaninbw Let me amend my post. \$\endgroup\$ – Stephen Feb 27 '20 at 0:25
  • \$\begingroup\$ @SamStafford This is going to be used for more complicated objects where you wouldn't want to just endlessly list the same parameters over and over. Something like d = {'a':{'b':{'c':{'d':'e'}}}} where the object is complex/deeply nested. \$\endgroup\$ – Stephen Feb 27 '20 at 0:25
  • \$\begingroup\$ You might want to read the guidelines for good questions at codereview.stackexchange.com/help/how-to-ask. \$\endgroup\$ – pacmaninbw Feb 27 '20 at 0:30
4
\$\begingroup\$

I think what you are doing is crazy, but yes, you can use Python’s library functions to clean it up.

from contextlib import contextmanager

@contextmanager
def context_wrap(target):
    yield target

Again, this is busy work.

alias = thing

is clearer, shorter and faster than

with context_wrap(thing) as alias:
\$\endgroup\$
4
  • \$\begingroup\$ Wow, this is extremely much cleaner than my solution. And I can see a few uses for it! Using a context manager doesn't leave a strong reference around in case something needs to be cleaned up by the garbage collector! I think it's especially useful for classes. \$\endgroup\$ – Stephen Feb 27 '20 at 16:55
  • \$\begingroup\$ alias will still be equal to thing after the with statement exits. It doesn't remove the variable, so a strong reference will still exist! \$\endgroup\$ – AJNeufeld Feb 27 '20 at 17:11
  • \$\begingroup\$ I think I have some more work to do then. But thanks for the help anyway! \$\endgroup\$ – Stephen Feb 27 '20 at 18:06
  • \$\begingroup\$ Trying to trick the Python garbage collector into cleaning things up at specific times is not going to be a fun game to play. Write it in Rust if object lifetimes are that important! :) \$\endgroup\$ – Samwise Feb 27 '20 at 18:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.