Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to accept both filenames and file-like objects in Python functions?

Tags:

In my code, I have a load_dataset function that reads a text file and does some processing. Recently I thought about adding support to file-like objects, and I wondered over the best approach to this. Currently I have two implementations in mind:

First, type checking:

if isinstance(inputelement, basestring):    # open file, processing etc # or # elif hasattr(inputelement, "read"): elif isinstance(inputelement, file):    # Do something else 

Alternatively, two different arguments:

def load_dataset(filename=None, stream=None):     if filename is not None and stream is None:         # open file etc     elif stream is not None and filename is None:         # do something else 

Both solutions however don't convince me too much, especially the second as I see way too many pitfalls.

What is the cleanest (and most Pythonic) way to accept a file-like object or string to a function that does text reading?

like image 678
Einar Avatar asked Sep 01 '11 09:09

Einar


People also ask

How do I read a filename from the path in Python?

To get a filename from a path in Python, use the os. path. basename() function.

How do you split a file name from a string in Python?

split() method in Python is used to Split the path name into a pair head and tail. Here, tail is the last path name component and head is everything leading up to that. In the above example 'file. txt' component of path name is tail and '/home/User/Desktop/' is head.

How do you access files in Python?

You can open a file using the open() function. The open() function takes two arguments - filename and mode. There are different access modes in which you can open a file.


2 Answers

One way of having either a file name or a file-like object as argument is the implementation of a context manager that can handle both. An implementation can be found here, I quote for the sake of a self contained answer:

class open_filename(object): """Context manager that opens a filename and closes it on exit, but does nothing for file-like objects. """ def __init__(self, filename, *args, **kwargs):     self.closing = kwargs.pop('closing', False)     if isinstance(filename, basestring):         self.fh = open(filename, *args, **kwargs)         self.closing = True     else:         self.fh = filename  def __enter__(self):     return self.fh  def __exit__(self, exc_type, exc_val, exc_tb):     if self.closing:         self.fh.close()      return False 

Possible usage then:

def load_dataset(file_):     with open_filename(file_, "r") as f:         # process here, read only if the file_ is a string 
like image 184
Percival Ulysses Avatar answered Oct 13 '22 06:10

Percival Ulysses


Don't accept both files and strings. If you're going to accept file-like objects, then it means you won't check the type, just call the required methods on the actual parameter (read, write, etc.). If you're going to accept strings, then you're going to end up open-ing files, which means you won't be able to mock the parameters. So I'd say accept files, let the caller pass you a file-like object, and don't check the type.

like image 44
Roshan Mathews Avatar answered Oct 13 '22 06:10

Roshan Mathews