Function isinstance, Class object, and Class Book

Function isinstance reports whether an object is an instance of a class—that is, whether an object has a particular type:

 >>>​​ ​​isinstance(​​'abc'​​,​​ ​​str)
 True
 >>>​​ ​​isinstance(55.2,​​ ​​str)
 False

’abc’ is an instance of str, but 55.2 is not.

Python has a class called object. Every other class is based on it:

 >>>​​ ​​help(object)
 Help on class object in module builtins:
 
 class object
  | The most base type

Function isinstance reports that both ’abc’ and 55.2 are instances of class object:

 >>>​​ ​​isinstance(55.2,​​ ​​object)
 True
 >>>​​ ​​isinstance(​​'abc'​​,​​ ​​object)
 True

Even classes and functions are instances of object:

 >>>​​ ​​isinstance(str,​​ ​​object)
 True
 >>>​​ ​​isinstance(max,​​ ​​object)
 True

What’s happening here is that every class in Python is derived from class object, and so every instance of every class is an object.

Using object-oriented lingo, we say that class object is the superclass of class str, and class str is a subclass of class object. The superclass information is available in the help documentation for a type:

 >>>​​ ​​help(int)
 Help on class int in module builtins:
 
 class int(object)

Here we see that class SyntaxError is a subclass of class Exception:

 >>>​​ ​​help(SyntaxError)
 Help on class SyntaxError in module builtins:
 
 class SyntaxError(Exception)

Class object has the following attributes (attributes are variables inside a class that refer to methods, functions, variables, or even other classes):

 >>>​​ ​​dir(object)
 ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
 '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
 '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__',
 '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
 '__subclasshook__']

Every class in Python, including ones that you define, automatically inherits these attributes from class object. More generally, every subclass inherits the features of its superclass. This is a powerful tool; it helps avoid a lot of duplicate code and makes interactions between related types consistent.

Let’s try this out. Here is the simplest class that we can write:

 >>>​​ ​​class​​ ​​Book:
 ...​​ ​​"""Information about a book."""
 ...

Just as keyword def tells Python that we’re defining a new function, keyword class signals that we’re defining a new type.

Much like str is a type, Book is a type:

 >>>​​ ​​type(str)
 <class 'type'>
 >>>​​ ​​type(Book)
 <class 'type'>

Our Book class isn’t empty, either, because it has inherited all the attributes of class object:

 >>>​​ ​​dir(Book)
 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
 '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
 '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__',
 '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
 '__str__', '__subclasshook__', '__weakref__']

If you look carefully, you’ll see that this list is nearly identical to the output for dir(object). There are three extra attributes in class Book; every subclass of class object automatically has these attributes in addition to the inherited ones:

 >>>​​ ​​set(dir(Book))​​ ​​-​​ ​​set(dir(object))
 {'__module__', '__weakref__', '__dict__'}

We’ll get to those attributes later on in this chapter in What Are Those Special Attributes?. First, let’s create a Book object and give that Book a title and a list of authors:

 >>>​​ ​​ruby_book​​ ​​=​​ ​​Book()
 >>>​​ ​​ruby_book.title​​ ​​=​​ ​​'Programming Ruby'
 >>>​​ ​​ruby_book.authors​​ ​​=​​ ​​[​​'Thomas'​​,​​ ​​'Fowler'​​,​​ ​​'Hunt'​​]

The first assignment statement creates a Book object and then assigns that object to variable ruby_book. The second assignment statement creates a title variable inside the Book object; that variable refers to the string ’Programming Ruby’. The third assignment statement creates variable authors, also inside the Book object, which refers to the list of strings [’Thomas’, ’Fowler’, ’Hunt’].

Variables title and authors are called instance variables because they are variables inside an instance of a class. We can access these instance variables through variable ruby_book:

 >>>​​ ​​ruby_book.title
 'Programming Ruby'
 >>>​​ ​​ruby_book.authors
 ['Thomas', 'Fowler', 'Hunt']

In the expression ruby_book.title, Python finds variable ruby_book, then sees the dot and goes to the memory location of the Book object, and then looks for variable title. Here is a model of computer memory for this situation:

images/oop/book1.png

We can even get help on our Book class:

 >>>​​ ​​help(Book)
 Help on class Book in module __main__:
 
 class Book(builtins.object)
  | Information about a book.
  |
  | Data descriptors defined here:
  |
  | __dict__
  | dictionary for instance variables (if defined)
  |
  | __weakref__
  | list of weak references to the object (if defined)

The first line tells us that we asked for help on class Book. After that is the header for class Book; the (builtins.object) part tells us that Book is a subclass of class object. The next line shows the Book docstring. Last is a section called “data descriptors,” which are special pieces of information that Python keeps with every user-defined class that it uses for its own purposes. Again, we’ll get to those in What Are Those Special Attributes?.