3

I have some lines in Python that I want to pass a function that for some reason only accepts inputs as filepaths. For the example, let's call this function func.read().

Since func.read() only knows how to reads files, not strings directly, I'm being forced to write my text into an auxiliary file and then pass the file path to func.read():

text="""some
random
text"""
fout = open("aux","wt")
fout.write(text)
fout.close()
func.read("aux")

But this is a hassle, and I'd like to avoid relying on writing external files. I could modify the function to take a string or list of strings, but this is a last case scenario (for some other reasons I can't go into detail here).

Is there a way I can "trick" this function by creating an object that behaves like a path to a file? Essentially an object that can be passed to open() I'd say.

Cheers

TomCho
  • 3,204
  • 6
  • 32
  • 83
  • I'm not sure I understand what you want exactly. Are you trying to take `text` in your example and pass it around somewhere? – kevin628 Nov 02 '16 at 23:32
  • @kevin628 I'm trying to pass `text` to `func.read`, but `func.read` only takes a file path, not a string. So I have to write my string into a file and then pass the path of that file to `func.read`. I'd like to avoid that. – TomCho Nov 02 '16 at 23:58
  • Yes, there is a way. I'll write up an answer here shortly. – kevin628 Nov 03 '16 at 00:04

1 Answers1

1

Yes, with duck typing. You can make an object that looks like a file object.

Because you only really need the read() method of a file object, you can make a class that also has a read() method on it. Simply create an instance of the class and pass it to the code dependent on read(). Whatever that dependent code is will be oblivious to the fact that you gave it a "fake" file object.

Here's an example.

class FileImitator:
    def __init__(self, contents_of_file):
        self.contents_of_file = contents_of_file

    def read(self):
        return self.contents_of_file

And here's a function that is expecting a file object, but I will give it an instance of my FileImitator instead:

def read_from_file(file):
    print(file.read())

imitation_file = FileImitator("Great Scott!")

read_from_file(imitation_file)  # prints "Great Scott!"

Of course, if I wanted to give it a real file object, I could do that, too:

def read_from_file(file):
    print(file.read())

real_file = open("/tmp/favorite-quotes.txt", "r")

read_from_file(real_file)  # prints out the contents of "favorite-quotes.txt"
kevin628
  • 3,458
  • 3
  • 30
  • 44
  • What am I missing? when I paste the first two boxes i get this error: " print(file.read()) TypeError: read() takes 0 positional arguments but 1 was given – Kyle Swanson Nov 03 '16 at 00:32
  • @KyleSwanson Don't pass any arguments to `read()` when you call it. The `read()` method doesn't take any parameters. – kevin628 Nov 03 '16 at 00:39
  • 1
    @KyleSwanson Actually, try the first two boxes again, as I have updated the code. – kevin628 Nov 03 '16 at 00:43
  • 2
    @kevin628 thanks for the attempt, but I don't need an object that has a `.read()` method, I need one that can be passed to an `open()` function! Such as `open(imitation_file)`. So I could read it with `open(imitation_file).read()`. – TomCho Nov 03 '16 at 06:12
  • I don't think that's possible, then, because `open()` only takes a string. There's no way to change what `open()` takes. – kevin628 Nov 04 '16 at 18:21