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?
To get a filename from a path in Python, use the os. path. basename() function.
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.
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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With