5

Is there a Python 2/3-compatible way of checking whether an object is a file?

I need to check if an object filehandler is actually a file object. This code needs to run in both Python 2 and 3. In Python 2 I could do

isinstance(filehandler, file)

However file is not part of Python 3, so this code raises a NameError when run with Python 3.

According to this answer, in Python 3 io.IOBase should be used to check if an object is a file, but Python 2's file doesn't subclass io.IOBase, so isinstance(filehandler, io.IOBase) won't work.

I thought about doing isinstance(filehandler, (io.IOBase, file)), but that still gives a NameError when I run it with Python 3.

Is there a way to do this that is compatible with both Python 2.7 and 3?

3 Answers 3

2

I found that the most common way of doing this is to check hasattr in Python 3. So, I added a check that will check the version of Python, and depending on that, it will execute the right function.

import sys

def isFile(f):
    return isinstance(f,file) if sys.version_info[0] == 2 else hasattr(f, 'read')        

f = open("post.php","r")
print(isFile(f))
print(isFile(10))

Alternatively, you can use a lambda, but I find it less readable.

isFile = lambda f:isinstance(f,file) if sys.version_info[0] == 2 else hasattr(f, 'read')   
Sign up to request clarification or add additional context in comments.

1 Comment

The point of a lambda is that it's an unnamed function, so if you need a named function there's no reason not to use a def. Far clearer and far more readable
1

This was the workaround I used: at the top of the .py file, I added:

import sys

if sys.version_info[0] == 3:
    from io import IOBase
    file = IOBase

So if Python 3 is being used, set file to be IOBase. Now isinstance(filehandler, file) will work correctly in Python 3, and for Python 2 it will work just like it always has.

Of course, this solution is extremely hackish and confusing, since it makes it look like IOBase is the Python 3 version of file, which is not the case. But it does solve the problem.

1 Comment

IOBase does not guarantee a file like object see for example >>> my_var = tempfile.NamedTemporaryFile() >>> my_var <tempfile._TemporaryFileWrapper object at 0x10206e198> >>> isinstance(z, io.IOBase) False
-1

Why not just do something like this

try:
    #check in py3
except:
    #check in py2

You can add some other error handlers if you want, but that should do.

4 Comments

I'm sure you meant except NameError: instead of a blanket except: correct?
yes that would probably be safer if you're relatively sure that's what you'll get
It' better to only catch what you know you will get than try to catch everything. If the code threw a ValueError because of some other unexpected reason then I imagine the blanket except would lead to difficult to debug errors.
This code block won't work, since using the Py3 check doesn't raise an error in Py2, it just gives the wrong answer. The Py2 and Py3 code need to be switched

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.