I am implementing my custom open() function (let's call it myOpen()). The task is, that I would like to be able to use this function also with with statement (with myOpen(...) as myFile:). As far as I know, open() must return file object (TextIO or BinaryIO). But open() in context of with statement is not a function, but class, that implements __enter__ and __exit__. Do you have any ideas, how to combine this two things together?
Thank you!
 
    
    - 31
- 2
- 
                    hope this helps https://stackoverflow.com/questions/53546824/multiple-ways-to-invoke-context-manager-in-python – Ade_1 Jun 04 '21 at 15:27
- 
                    This post explains how to use `__enter__` and `__exit__` in a with expression: https://stackoverflow.com/questions/1984325/explaining-pythons-enter-and-exit – David Kaftan Jun 04 '21 at 15:38
- 
                    When you use `with x() as y`, it is effectively assigning `y = x().__enter__()` – Peter Jun 04 '21 at 15:41
- 
                    @Peter calling `with x() as y`, where `x()` is function, is giving me `AttributeError: __enter__` (Python 3.9.5) – wynxel Jun 04 '21 at 16:21
- 
                    Ah nvm, I reread the question, the answer is no you can't combine a context manager and a function to do both things what once. What you can do however is design a class in a way where the logic is done in `__init__` and just have `def __enter__(self): return self`. That way you get the same result with or without using `with`. – Peter Jun 04 '21 at 19:54
2 Answers
Using a with statement still returns a _io.x class.
>>> type(open('_file_'))
<class '_io.TextIOWrapper'>
>>> with open('_file_') as o: print(type(o))
... 
<class '_io.TextIOWrapper'>
The with statement just assigns another variable for a block of code.
Example:
def five():
    return 5
print(five()) # -> 5
print(type(five())) # -> int
with five() as x:
    print(x) # -> 5
    print(type(x)) # -> int
print(x) # -> 5
The with statement is equivalent to
x = five()
print(x)
print(type(x))
or, for the FileIO:
handle = open('_file_')
# do things with handle
- 
                    Thank you, well, `with five() as x` gives me `AttributeError: __enter__` (python 3.9.5). Another question would be how can I handle `__exit__` in `myOpen()`? How can I close file descriprot in `myOpen()` function, when `with` statement exists? – wynxel Jun 04 '21 at 16:16
- 
                    make a class with for your special filehandle, with `__enter__` and `__exit__` methods. – Jun 07 '21 at 12:56
Well, I figured out where was a problem. At the beginning I thought, that with statement can be called only on class, which has those magic methods (__enter__ and __exit__). So:
with class_that_has_those_methods as return_value_from_enter:
    pass
But it works different. Expression after with can be also function, but it has to return instance of class, which implements those magic methods. I think, that this is also the way, how python's open works. It is function, which returns file object (more precisely wrapper):
>>> type(open)
<class 'builtin_function_or_method'>
>>> type(open('file', 'w'))
<class '_io.TextIOWrapper'>
and that file object implements those magic methods:
>>> a = open('file', 'w')
>>> dir(a)
[... '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', ...]
So to solve my original problem, myOpen() has to be function, which returns file object, that has __enter__ and __exit__ methods.
 
    
    - 31
- 2