4

I have a five or six resources that have nice 'with' handlers, and normally I'd do this:

with res1, res2, res3, res4, res5, res6:
   do1
   do2

However, sometimes one or more of these resources should not be activated. Which leads to very ugly repetitive code:

 with res1, res3, res4, res6: # these always acquired
    if res2_enabled:
        with res2:
           if res5_enabled:
               with res5:
                  do1
                  do2
           else:
              do1
              do2
     else if res5_enabled:
        with res5:
           ...

There must be clean easy ways to do this surely?

1
  • Have you considered adding the appropriate resources in a list, using with res_list: and (if necessary) iterating through the res_list inside the with statement? Since I'm not sure what you're doing or how it uses the resources, I can't provide a much better answer... Are the individual resources passed as function parameters? You might try a dictionary if the name is important, too, such as res_dict = {}; res_dict['res1'] = <res1>; res_dict['res2'] = <res2>; .... Commented Jun 18, 2011 at 23:43

3 Answers 3

6

You could create a wrapper object that supports the with statement, and do the checking in there. Something like:

with wrapper(res1), wrapper(res2), wrapper(res3):
   ...

or a wrapper than handles all of them:

with wrapper(res1, res2, res3):
   ...

The definition for you wrapper would be:

class wrapper(object):
    def __init__(self, *objs):
        ...

    def __enter__(self):
        initialize objs here

    def __exit__(self):
        release objects here
Sign up to request clarification or add additional context in comments.

Comments

5

If I understand you correctly you can do this:

from contextlib import contextmanager, nested

def enabled_resources(*resources):
    return nested(*(res for res,enabled in resources if enabled))

# just for testing
@contextmanager
def test(n):
    print n, "entered"
    yield

resources = [(test(n), n%2) for n in range(10)]
# you want
# resources = [(res1, res1_enabled), ... ]

with enabled_resources(*resources):
    # do1, do2
    pass

Comments

0

Original Poster here; here is my approach refined so far:

I can add (or monkey-patch) the bool operator __nonzero__ onto the with objects, returning whether they are enabled. Then, when objects are mutually exclusive, I can have:

with res1 or res2 or res3 or res4:
   ...

When an resource is togglable, I can create an empty withable that is a nop; wither seems a nice name for it:

class sither:
   @classmethod
   def __enter__(cls): pass
   @classmethod
   def __exit__(cls,*args): pass

...

with res1 or wither, res2 or wither:
   ...

I can also use this keeping the toggling out of the withable objects:

with res1 if res1enabled else wither, res2 if res2enabled else wither:
   ..

Finally, those I have most control over, I can integrate the enabled checking into the class itself such that when used and not enabled, they are nop:

with res1, res2, res3:
   ...

The with statement is absolutely adorable, it just seems a bit unentrenched yet. It will be interesting to see what finesse others come up with in this regard...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.