5

In Python 2.7 I get the following results:

>>> with open("README.md", "r") as fin:
...     print(isinstance(fin, file))
... 
True

In python 3.5 I get:

>>> with open("README.md", "r") as fin:
...     print(isinstance(fin, file))
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
NameError: name 'file' is not defined

So, OK I look at the Python docs and find out that in Python 3.5, files are of type io.IOBase (or some subclass). Leading me to this:

>>> import io
>>> with open("README.md", "r") as fin:
...     print(isinstance(fin, io.IOBase))
... 
True

But then when I try in Python 2.7:

>>> import io
>>> with open("README.md", "r") as fin:
...     print(isinstance(fin, io.IOBase))
... 
False

So at this point, I'm confused. Looking at the documentation, I feel as though Python 2.7 should report True.

Obviously I'm missing something elementary, perhaps because it's 6:30 PM ET, but I have two related questions:

  1. Why does Python report False for isinstance(fin, io.IOBase)?
  2. Is there a way to test that a variable is an open file which will work in both Python 2.7 and 3.5?
iLoveTux
  • 3,552
  • 23
  • 31

2 Answers2

7

From the linked documentation:

Under Python 2.x, this is proposed as an alternative to the built-in file object

So they are not the same in python 2.x.

As to part 2, this works in python2 and 3, though not the prettiest thing in the world:

import io
try:
    file_types = (file, io.IOBase)

except NameError:
    file_types = (io.IOBase,)

with open("README.md", "r") as fin:
    print(isinstance(fin, file_types))
Ilja Everilä
  • 50,538
  • 7
  • 126
  • 127
  • Since it's just for `isinstance` checks, you don't need the `tuple` wrapping in the Py3 case; just `file_types = io.IOBase` would work (possibly slightly more efficiently). – ShadowRanger Mar 30 '16 at 23:01
  • 1
    @ShadowRanger aye, but kept it for consistency + the name of the variable indicates a sequence. Not that keen on optimizing such stuff unless really needed. – Ilja Everilä Mar 30 '16 at 23:03
  • 2
    OK, so I'm marking this answer as correct because I feel it's the correct answer to my question, but since my ultimate goal is to have a Python 2.7 and 3.5 compatible code base, I'm actually switching my `open()` calls to `io.open()` calls which work in both versions and you can test them the same way. Thanks for your help. – iLoveTux Mar 30 '16 at 23:06
  • @iLoveTux using io.open has the added benefit of `encoding=...`, `newline=...` support in Py2 too. – Ilja Everilä Mar 30 '16 at 23:07
  • @IIja, awesome! I'm sure that making this change will ultimately lead to more compatible code and it's just one more import and three more keystrokes per file. I can't believe I couldn't find anything online about this before. I'm just now getting into Python 3, so I'm sure there is a lot more to learn. Anyway, thank you for everything, including the quick response. – iLoveTux Mar 30 '16 at 23:11
1

For python2

import types
f = open('test.txt', 'r')   # assuming this file exists
print (isinstance(f,types.FileType))

For python3

import io
import types
f1 = open('test.txt', 'r')   # assuming this file exists
f2 = open('test.txt', 'rb')   # assuming this file exists
print (isinstance(f1,io.IOBase))
print (isinstance(f2,io.IOBase))

(Edit: my previous solution tested for io.TextIOWrapper, it worked only with files opened in text mode. See https://docs.python.org/3/library/io.html#class-hierarchy which describes the python3 class hierarchy).

Sci Prog
  • 2,651
  • 1
  • 10
  • 18