0

Disclaimer: The word subclass in the title is not correct, but this is a reference to the old pytho2 only solution and I didn't know any better way of describing it.

The objective: I am looking for a way, that lets me do following in my existing code

  • import MyFile at the beginning of a file
  • 'just' replace open with either MyFile
  • replace open(*args, *kwargs) with MyFile(*args, *kwargs, special_param=True)

The code should behave exactly as before, but trigger some additional behavior at the opening time (before or after opening) of the file and when some methods are called (e.g. close() before or after closing)

With exactly as before I mean, that the code is still working if I would replace globally open( with MyFile( (and add of course the import for MyFile

open is not a class and can therefore not be subclassed. The old python2 only version however was implemented by subclassing file (which is also not a class AFAIK, but the solution worked)

The old python2 only solution:

class MyFile(file):
    def __init__(self, fname, mode, special_param=False):
        # next line would be nice, but is not essential
        # do_something_special_before_opening(self, special_param)
        super(MyFile, self).__init__(fname, mode)
        do_something_special_after_opening(self, special_param)
    
    def close(self):
        super(MyFile, self).close()
        do_something_special_after_closing(self)

The way it would be used is:

from mymodule import MyFile
# and then use MyFile in the rest of the file

or

from mymodule import MyFile as open
# keep the rest of the file unchanged

As file doesn't exist anymore in python.

There is already an answer on SO ( Porting a sub-class of python2 'file' class to python3 ) However this does not answer my question, as it suggests to inherit from io.FileIO, as it expects bytes to be written and not strings.

What is the best way to implement such a feature in python3 (should work for Linux and Windows)

In python3 the result of open() does not always belong to the same class.

Example: If opening in text mode a _io.TextIOWrapper object is returned. If opening in binary write mode a _io.BufferedWriter or _io.BufferedReader is returned. If opening in binary mode with buffering=0 then _io.FileIO is returned.

So one option could be to subclass _io.TextIOWrapper, _io.BufferedWriter, _io.BufferedReader, _io.FileIO, ... and create a factory returning one of these sub classes.

However I wonder if there's a more elegant way. With above approach I had to create quite some sub classes and to reimplement the entire logic of open, that determines which class to use for which combination of parameters.

Perhaps there is some trick with monkeypatching?

gelonida
  • 5,327
  • 2
  • 23
  • 41
  • It would help to have examples of how your class is expected to be used and behave – Iain Shelvington Sep 30 '20 at 01:31
  • 2
    Does this answer your question? [Porting a sub-class of python2 'file' class to python3](https://stackoverflow.com/questions/47838405/porting-a-sub-class-of-python2-file-class-to-python3) – smac89 Sep 30 '20 at 01:56
  • @smac89. I will check the answer and see whether it really solves my issue. At a very first glance I think it doesn't but I will look at it more carefully – gelonida Sep 30 '20 at 02:45
  • @IainShelvington: I enhanced my question. Though I can't elaborate on the behavior I hope, this clarifies – gelonida Sep 30 '20 at 02:49
  • What about a class that uses `open` upon instantiation and implements a `close` method? – jkr Sep 30 '20 at 22:43
  • @jakub well that class had to relay all unmodified methods and attributes to the object returned by `open()`m but this might be an option. – gelonida Oct 01 '20 at 00:06
  • I believe you are overthinking this. Firstly how are you complaining that `io.FileIO` only allows writing bytes, when `io.BufferedWriter` does the same? Secondly, why are you trying to reinvent the `open` method when all you really need is to write some strings? You should focus on abstracting the operations of the class to fit your needs, rather than worrying about how python implemented the `open` method. At the end of the day, the OS does not care about strings, only bytes matter; so why even let this become an obstacle? At most, you just need to call `string.encode(...)` to get bytes. – smac89 Oct 01 '20 at 02:47
  • @smac89 I do not understand your comment. Did you reread the section "The objective:" of my question. I thought it is clearer now, but perhaps not. I have a huge projects with loads of `open()` commands. Some of them shall require special actions (hooks) but should otherwise behave **exactly** as before, without having to change any other lines These sections could be anything, but let's imagine for example: - mounting a device pre-open - unmount a device post-close - add counters of written / read bytes for every read / write – gelonida Oct 01 '20 at 10:12
  • enhanced question. hopefully clearer now – gelonida Oct 01 '20 at 10:16

0 Answers0