21

How can I use isinstance to determine the 'type' of a file object, such as in the expression:

>>> open(file)
Asclepius
  • 57,944
  • 17
  • 167
  • 143
Aleeee
  • 1,913
  • 6
  • 17
  • 27
  • 1
    What do you mean by judging the type of open(file)? Do you mean the type of the text in the file(e.g. int, string)? – Vedaad Shakib Jul 01 '14 at 02:03
  • 6
    If you encounter this question looking for an appropriate type hint in Python3, use TextIO imported from `typing` (e.g. `from typing import TextIO` in the "preamble" and then `file_handle : TextIO = open(...)` in your code. – mutableVoid Jun 16 '21 at 11:26

4 Answers4

29

In Python 3.x, normal file objects are of type io.TextIOWrapper:

>>> type(open('file.txt'))
<class '_io.TextIOWrapper'>

>>> from io import TextIOWrapper
>>> isinstance(open('file.txt'), TextIOWrapper)
True

In Python 2.x, all file objects are of type file:

>>> type(open('file.txt'))
<type 'file'>

>>> isinstance(open('file.txt'), file)
True
Asclepius
  • 57,944
  • 17
  • 167
  • 143
  • 4
    Most of the time, you don't really care, though. You care that it's an iterable of lines, or that it has a `read` method or a `write` method, or something else relating to the file interface. That's what you should be checking, usually by simply trying to use the object like a file and catching the error if it doesn't support the interface you need. – user2357112 Jul 01 '14 at 02:59
  • 1
    FYI, open a file in binary mode `open('file.txt', 'rb')` results in `` type. – Rick Aug 14 '19 at 06:07
  • 3
    `TextIOWrapper` is what is returned if you open in default/ text mode, `BufferedReader` is what you get in binary ('b') mode, so you can check for either individually or just use their superclass `IOBase` if you want to catch both – AndrewWhalan Apr 09 '20 at 06:16
7

One can pick their preference from the IO class hierarchy. This answer builds upon the previous answer by user2555451 and its comments. The one-line summary is at the end of the answer.

For text files, io.TextIOBase can be acceptable:

>>> import io

>>> type(f := open('/tmp/foo', 'w'))
<class '_io.TextIOWrapper'>
>>> isinstance(f, io.TextIOBase)
True

>>> f.__class__.__bases__
(<class '_io._TextIOBase'>,)
>>> f.__class__.__mro__
(<class '_io.TextIOWrapper'>, <class '_io._TextIOBase'>, <class '_io._IOBase'>, <class 'object'>)

For text files, avoid io.TextIOWrapper because it does not also work for io.StringIO:

>>> isinstance(io.StringIO('foo'), io.TextIOWrapper)
False
>>> isinstance(io.StringIO('foo'), io.TextIOBase)
True

For binary files, io.BufferedIOBase can be acceptable:

>>> import io

>>> type(f := open('/tmp/foo', 'wb'))
<class '_io.BufferedWriter'>
>>> isinstance(f, io.BufferedIOBase)
True

>>> f.__class__.__bases__
(<class '_io._BufferedIOBase'>,)
>>> f.__class__.__mro__
(<class '_io.BufferedWriter'>, <class '_io._BufferedIOBase'>, <class '_io._IOBase'>, <class 'object'>)

For binary files, avoid io.BufferedReader or io.BufferedWriter because they do not also work for io.BytesIO:

>>> isinstance(io.BytesIO(b'foo'), io.BufferedReader)
False
>>> isinstance(io.BytesIO(b'foo'), io.BufferedWriter)
False
>>> isinstance(io.BytesIO(b'foo'), io.BufferedIOBase)
True

To support both text and binary files, io.IOBase is acceptable:

>>> import io

>>> isinstance(open('/tmp/foo', 'w'), io.IOBase)
True
>>> isinstance(open('/tmp/foo', 'wb'), io.IOBase)
True

In summary, I would typically pick io.TextIOBase for text files, io.BufferedIOBase for binary files, and io.IOBase for nonspecific files.

Asclepius
  • 57,944
  • 17
  • 167
  • 143
1

As stated in the documentation for open:

Open a file, returning an object of the file type described in section File Objects.

Thus, open returns a file, and you should use isinstance(foo, file)

jwodder
  • 54,758
  • 12
  • 108
  • 124
0

Its type is file. You can tell by the output of type(open("file","w"))

Nick Retallack
  • 18,986
  • 17
  • 92
  • 114