Kyle Truong
Kyle Truong

Reputation: 2751

Where is a Python built-in object's __enter__() and __exit__() defined?

I've read that the object's __ enter__() and __ exit__() methods are called every time 'with' is used. I understand that for user-defined objects, you can define those methods yourself, but I don't understand how this works for built-in objects/functions like 'open' or even the testcases.

This code works as expected and I assume it closes the file with __ exit__():

with open('output.txt', 'w') as f:
    f.write('Hi there!')

or

with self.assertRaises(ValueError):
    remove_driver(self.driver)  # self refers to a class that inherits from the default unittest.TestCase

Yet, there's no such __ enter__() or __ exit__() method on either object when I inspect it:

enter image description here

enter image description here

So how is 'open' working with 'with'? Shouldn't objects that support context management protocol have __ enter__() and __ exit__() methods defined and inspectable?

Upvotes: 4

Views: 1988

Answers (4)

Exlife
Exlife

Reputation: 99

when you open a text file for reading or writing, the build-in open() function return an instance of TextIOWrapper class.

From the textio.c source code we can see the class tree is:

IOBase <- TextIOBase <- TextIOWrapper

The IOBase has defined __enter__ and __exit__ functions and in __exit__ function it calls close().

The TextIOWrapper class inherits these methods from IOBase, and makes "with" statement works.

Upvotes: 0

zondo
zondo

Reputation: 20366

open() is a function. It returns something that has an __enter__ and __exit__ method. Look at something like this:

>>> class f:
...     def __init__(self):
...         print 'init'
...     def __enter__(self):
...         print 'enter'
...     def __exit__(self, *a):
...         print 'exit'
... 
>>> with f():
...     pass
... 
init
enter
exit
>>> def return_f():
...     return f()
... 
>>> with return_f():
...     pass
... 
init
enter
exit

Of course, return_f itself does not have those methods, but what it returns does.

Upvotes: 11

Tadhg McDonald-Jensen
Tadhg McDonald-Jensen

Reputation: 21474

open is a function that returns a file object with the context methods, and self.assertRaises is a method that returns an object with the context methods, try checking the dir of their return value:

>>> x = open(__file__, "r")
>>> x
<_io.TextIOWrapper name='test.py' mode='r' encoding='US-ASCII'>
>>> type(x)
<class '_io.TextIOWrapper'>
>>> "__exit__" in dir(x)
True

Upvotes: 6

user2357112
user2357112

Reputation: 281958

You're checking whether the open function itself or the assertRaises method itself has __enter__ and __exit__ methods, when you should be looking at what methods the return value has.

Upvotes: 2

Related Questions