5

A common requirement in my Python packages is to allow for a file input either as a string filename, a pathlib.Path, or an already opened buffer. I usually separate out the buffer like

def foo_from_file(filename, *args, **kwargs):
    with open(filename) as f:
        foo_from_buffer(f, *args, **kwargs)


def foo_from_buffer(f):
    f.readline()
    # do something
    return

but a cleaner approach from a user's perspective would probably be

def foo(file_or_buffer):
    if hasattr(file_or_buffer, "readline"):  # ???
        f = file_or_buffer
    else:
        f = open(file_or_buffer)

    f.readline()

(This particular implementation isn't very nice because it doesn't close() on failure.)

Is file_or_buffer a common argument in Python methods or do you separate between the two? How to best implement it?

1 Answer 1

2

Adapting from a similar type of question I had regarding an already-open database connection that could have been passed in as a parameter or not, you can use a nullcontext to "do nothing" when whatever you pass in has readline:

from contextlib import nullcontext
from pathlib import Path
from io import StringIO

def foo(file_or_buffer):
    if hasattr(file_or_buffer, "readline"):
        cm = nullcontext(file_or_buffer)
    else:
        cm = open(file_or_buffer)

    with cm as f:
        line = f.readline()
        print(line)
    
pa = Path(__file__)

foo(pa)
foo(f"{pa}")

with pa.open() as fi:
    foo(fi)
with pa.open() as fi:
    buffer = StringIO(fi.read())
foo(buffer)

output:

from contextlib import nullcontext

from contextlib import nullcontext

from contextlib import nullcontext

from contextlib import nullcontext
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.