Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to accept file or path as arguments to method in python

Tags:

python

file

I am trying to write a method that will accept either an opened file

myFile = open("myFile.txt")
obj.writeTo(myFile)
myFile.close()

or a string with a path

obj.writeTo("myFile.txt")

The method is implemented as follows:

def writeTo(self, hessianFile):
    if isinstance(hessianFile,file):
        print("File type")
    elif isinstance(hessianFile,str):
        print("String type")
    else:
        pass

But this raises an error

NameError: global name 'file' is not defined

why is file type not defined? Shouldn't file be defined all the time? How should the implementation be corrected to properly handel both path an file as valid argument types

like image 333
Andrew Hoos Avatar asked Oct 19 '25 16:10

Andrew Hoos


1 Answers

Don't type check! It's not Pythonic. The core of duck typing is the idea that if it quacks like a duck, it is a duck. The behaviour you want is if it is file-like, it works, and if it is string-like, it works. This isn't just ideological - because this is the standard in Python, people will expect to be able to give you a file-like object and have it work. If you restrict it to only a specific file type, your code will be fragile and inflexible.

The simplest option is to simply pick the more common outcome, try to work as you would with that, and fail to the other method if you get an exception:

def writeTo(self, hessianFile):
    try:
        with open(hessianFile, "w") as f:
            do_stuff(f)
    except TypeError:
        do_stuff(hessianFile)

This might seem bad if you are used to other languages where "using exceptions for flow control" is considered bad, but that isn't the case in Python, where they are a core part of the language regularly used that way (every for loop ends with an exception!).

Or, if you think you are more likely to get a file object most of the time, do it the other way around:

def writeTo(self, hessianFile):
    try:
        do_stuff(f)
    except AttributeError:
        with open(hessianFile, "w") as f:
            do_stuff(f)

Note my use of the with statement which is the best way of dealing with opening files - it's more readable, and also always closes the file for you, even on exceptions.

If you really find you have to type check (e.g: the operation is extremely expensive even if it fails, with no way to short-circuit), you should check the string side, as it is easier to work out if something is string-like as opposed to file-like. If you have to check for something file-like, you should implement an abstract base class and look for the functionality you need, rather than actually type-checking.

The reason your original code failed is that file isn't the base class of objects returned by open() in 3.x.

The type of file object returned by the open() function depends on the mode. When open() is used to open a file in a text mode ('w', 'r', 'wt', 'rt', etc.), it returns a subclass of io.TextIOBase (specifically io.TextIOWrapper). When used to open a file in a binary mode with buffering, the returned class is a subclass of io.BufferedIOBase. The exact class varies: in read binary mode, it returns a io.BufferedReader; in write binary and append binary modes, it returns a io.BufferedWriter, and in read/write mode, it returns a io.BufferedRandom. When buffering is disabled, the raw stream, a subclass of io.RawIOBase, io.FileIO, is returned. Source

So for that you want io.FileIO.

like image 98
Gareth Latty Avatar answered Oct 22 '25 06:10

Gareth Latty



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!