开发者

conditional python with

开发者 https://www.devze.com 2023-03-14 02:11 出处:网络
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:

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?


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


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


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...

0

精彩评论

暂无评论...
验证码 换一张
取 消