-1

Say have a python function foo() that uses some resource and is meant to be called as follows:

   with foo(x,y,z) as f:
       doSomething(f)

So far so good. Now lets say foo takes in a complex set of arguments based on a variety of factors, and I'd like to define a wrapper function to make things simpler. Something like:

def simple_foo():
    if x:
       return foo(a,b,c)
    else:
       return foo(d,e,f)

Now, I'd like to use simple_foo in place of foo, like:

with simple_foo() as f:
    doSomething(f)

However, unsurprisingly, this does not work. How can I write simple_foo() to get this behavior?

chessprogrammer
  • 768
  • 4
  • 15
  • 2
    It's called a context manager - take a look at the example [here](https://stackoverflow.com/a/36559849/5858851) – pault Jun 25 '19 at 17:25
  • 3
    "However, unsurprisingly, this does not work." How does this not work, *exactly*? – juanpa.arrivillaga Jun 25 '19 at 17:36
  • @juanpa.arrivillaga gives:AttributeError: __aexit__ – chessprogrammer Jun 25 '19 at 17:38
  • 2
    If ˋfooˋ is a proper context manager, this *does* work. There is no magic to constructing a context manager inside a ˋwithˋ as opposed to outside one. What *exactly* is your problem? – MisterMiyagi Jun 25 '19 at 17:40
  • @chessprogrammer what? Pleases edit your post with a [mcve], including full error messages – juanpa.arrivillaga Jun 25 '19 at 17:40
  • @MisterMiyagi thank you for your insightful comment. You were right that I had misunderstood. I guess the correct answer to my question is:"This does work as stated, your premise was wrong." – chessprogrammer Jun 25 '19 at 18:12
  • If it gives an attribute error of `__aexit__`, this should be an async context manager, but even then `simple_foo` should still work. – GeeTransit Jun 25 '19 at 19:22

2 Answers2

1

Decorate function foo() with contextmanager (doc):

from contextlib import contextmanager

@contextmanager
def foo(a, b, c):
    try:
        yield a + b + c
    finally:
        pass

def simple_foo(x):
    if x:
        return foo(1, 2, 3)
    return foo(4, 5, 6)

with simple_foo(True) as v:
    print(v)

with simple_foo(False) as v:
    print(v)

Prints:

6
15
Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
1

You can do by writing a custom context manager that internally calls that function, try code given below:

class SimpleFoo:

   def __init__(self,x,y,z, option):
       self.x = x
       self.y = y
       self.z = z
       self.option = option


    def __enter__(self):
       if self.option:
          return foo(self.x,self.y,self.z)
       else:
          return foo(self.y,self.z,self.x)

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

       if type != None:
           print("Error in SimpleFoo")
           print("Error Type :", type)
           print("Error Value :", value)
           print("Error Traceback :", traceback)
           self.status = value

Now if you want to use this, use it as below:

with SimpleFoo(1,2,3,True) as foo:
     doSomething(foo)

I hope this helps.

Shishir Naresh
  • 743
  • 4
  • 10
  • 1
    You can do code block with three backticks (```) (the key below `esc`) to properly format you code instead of using 4 spaces for each line. Your class wasn't properly indented. – Error - Syntactical Remorse Jun 25 '19 at 17:40