-1

Newer to Python and am experimenting with creating my own Context Manager for calling Login/Logout methods of a certain REST API. That way I can do other API things and Login/Logout will be handled for me. However, I'm confused on the behavior of the return statement inside the with statement in the below code. I would expect it to return back to code execution outside the with block but it instead exits the entire __enter__ function? Why is that?

# test.py

import requests

class LoginLogoutContextManager:
    def __enter__(self):

        print("**entered __enter__")
        print("Logging in...")

        # --- Login --- #

        # Let's pretend this GET request
        # is the Login Code

        self.url = "http://www.google.com"
        self.session = requests.Session()

        with self.session.get(self.url) as self.response:
            print("Start Login attempt (inside WITH but before RETURN)")
            return len(self.response.content)
            print("Login complete (inside WITH but after RETURN)")

        # !!! Login Code finished !!! #

        # OK login code is now done and we're out of the WITH statement

        print("I would expect the above WITH block to Return to here")
        print("!!exiting __enter__")

    def __exit__(self, exc_type, exc_value, exc_tb):

        print("**entered __exit__")
        print("Logging OUT...")

        # Logout code goes here

        print("!!exiting __exit__")


with LoginLogoutContextManager() as manager:
    print("Cool now the Login/Logout API calls are handled for me")

    # Does other API things here

    print(f"Login attempt response length: {manager}")
# python3 test.py

**entered __enter__
Logging in...
Start Login attempt (inside WITH but before RETURN)
Cool now the Login/Logout API calls are handled for me
Login attempt response length: 14126
**entered __exit__
Logging OUT...
!!exiting __exit__
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • 1
    Out of curiosity, what gave you the impression that `return` has a different meaning inside a `with` block? Is there a particular passage from a book or tutorial? – Brian61354270 Jan 20 '23 at 23:54
  • I always thought that `return` exits the current function, and seeing as I'm using `return` inside a `with` statement (which is its own function), I would expect that `return` statement to exit the `with` "function" and return control to the "parent" function (in this case the `__enter__` function. – Jones Smith Jan 21 '23 at 15:06

1 Answers1

1

I would expect it to return back to code execution outside the with block

You may expect that but it's not true.

but it instead exits the entire __enter__ function? Why is that?

The language reference specifies it so:

https://docs.python.org/3/reference/simple_stmts.html#the-return-statement

return leaves the current function call with the expression list (or None) as return value.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • So I guess that's where my confusion is. I just posted this in a comment above also, but I agree that that `return` exits the current function, and seeing as I'm using `return` inside a `with` statement (which is its own class/function with its own `__enter__` and `__exit__` functions, right?), I would expect that `return` statement inside the `with` class/function to exit that nested `with` class/function and return control to my "parent" function (in this case my `__enter__` function). – Jones Smith Jan 21 '23 at 15:09
  • ah wait, the code inside the `with` block is actually not running "inside" the `with` block, but is running in the context of the "parent" function so the `return` statement would actually be in the context of the parent function. – Jones Smith Jan 21 '23 at 15:25