Reputation: 5195
In the code below I don't understand why the with super().__init__(*args, **kwargs):
line in MyFileIO2 is throwing an error about missing __exit__
while everything works perfectly fine with the MyFileIO class. I don't really understand what exactly the difference between doing the with inside or outside of the init is. Can someone enlighten me what is going on here?
import io
class MyFileIO(io.FileIO):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def __enter__(self, *args, **kwargs):
f = super().__enter__(*args, **kwargs)
print('first byte of file: ', f.read(1))
return f
class MyFileIO2(io.FileIO):
def __enter__(self, *args, **kwargs):
f = super().__enter__(*args, **kwargs)
print('first byte of file: ', f.read(1))
return f
def __init__(self, *args, **kwargs):
with super().__init__(*args, **kwargs): # AttributeError: __exit__
pass
path = 'some_file.bin'
with MyFileIO(path, 'rb'):
pass
MyFileIO2(path, 'rb')
Upvotes: 0
Views: 952
Reputation: 403278
You will need to call the context manager on self
, because __init__
doesn't actually return anything.
class MyFileIO2(io.FileIO):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
with self:
pass
def __enter__(self, *args, **kwargs):
f = super().__enter__(*args, **kwargs)
print('First byte of file: ', f.read(1))
return f
For testing, I created a binary file having the contents "hello world".
_ = MyFileIO2(path, 'rb')
# First byte of file: b'h'
What happens is the return value of super().__init__
is being passed through the context manager, so you effectively have this:
with None:
pass
AttributeError: __enter__
The context manager tries calling the __enter__
method on the NoneType
object, but that is an invalid operation.
Upvotes: 1