5

From Python's source code of open, I think open is just a normal function.

Why can we use it like below?

with open('what_are_context_managers.txt', 'r') as infile:
    for line in infile:
        print('> {}'.format(line))

Since is neither implements __enter__ nor __exit__, nor uses contextlib.contextmanager decorator.

Peter Wood
  • 23,859
  • 5
  • 60
  • 99
scriptboy
  • 777
  • 8
  • 25
  • 6
    The original `file` type that is returned by the function implements the context manager interface. – Klaus D. May 03 '17 at 10:15

1 Answers1

18

You are not using the open function as a context manager. It is the result of the open(...) call expression that is the context manager. open() returns a file object, and it is that object that has __enter__ and __exit__ methods; see the io.IOBase documentation:

IOBase is also a context manager and therefore supports the with statement.

You can read the with statement like this:

_context_manager = open('what_are_context_managers.txt', 'r')
with _context_manager as infile:

Note that it is the return value of _context_manager.__enter__() that ends up being assigned to infile here. For file objects, file.__enter__() returns self, so you can get access to the same object that way.


As a side-note; you got the wrong open() function. The actual definition of the open() built-in is an alias for io.open(), see the _iomodule.c source code. The alias is set in initstdio() in pylifecycle.c (where io.OpenWrapper is itself an alias for _io.open). And yes, the documentation states the alias points the other way for end-user ease.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343