34

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

>>> open(file)
2
  • 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)? Commented Jul 1, 2014 at 2:03
  • 9
    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. Commented Jun 16, 2021 at 11:26

5 Answers 5

33

These are for use with isinstance.

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
Sign up to request clarification or add additional context in comments.

4 Comments

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.
FYI, open a file in binary mode open('file.txt', 'rb') results in <class '_io.BufferedReader'> type.
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
Here is how to type hint a file object.
20

For type hints only

For type hints only, I would consider typing.TextIO for text files, typing.BinaryIO for binary files, and typing.IO for nonspecific files.

Note that these will not work with isinstance!

For isinstance

For use with isinstance, 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, for use with isinstance, I would typically pick io.TextIOBase for text files, io.BufferedIOBase for binary files, and io.IOBase for nonspecific files.

Comments

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)

Comments

0

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

1 Comment

This is outdated.
0

Beware of 'file-like' objects

Unless you know exactly that the code sending you that file-ish object will use standard manners of producing them, any assumption about the type will be risky.

That is because Python frequently uses the notion of 'file-like' objects: Objects that may indeed be something else entirely, but support enough of the file operations for a given purpose -- possibly nothing but read(). They are mentioned for instance at module io, shutil.copyfileobj, zipfile.ZipFile, and even in the Python glossary.

For a possible solution, see the discussion of typing.Protocol at https://stackoverflow.com/a/78880231 and https://stackoverflow.com/a/76575571.

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.