Skip to content

Instantly share code, notes, and snippets.

@jomido
Last active February 9, 2017 16:15
Show Gist options
  • Save jomido/2fcadbc63a4d8adc1fb89d9753a08363 to your computer and use it in GitHub Desktop.
Save jomido/2fcadbc63a4d8adc1fb89d9753a08363 to your computer and use it in GitHub Desktop.
What is a Class?

What is a class?

A class is a type. A type of thing. There are lots of cars, but there are also lots of types of cars. A Porsche 911 is such a type. If you go out onto a road, you will see lots of cars, and you will be able to identify their types. But what you will definitely not see is the type or class itself. Just instances of that type.

A class or type is defined by its properties and abilities. Another way to think of a class is as a table schema in a database. The schema defines the columns via a name and a kind of data. That is, it defines the table's type, or its class. Individual rows inside the table are instances of the type.

In addition, types (or classes) of things seem to be arranged in a hierarchy. A Porsche 911 is a type of car that has instances in the real world. But a Porsche 911, while being a type, belongs to yet another type called "motor vehicle". There are people and birds and lamp posts on the street too, none of which are types of motor vehicles. "Motor vehicle" is a parent type of "Porsche 911". "Motor Vehicle" is more general, and contains more of the things in the real world than the "Porsche 911" type. (There are more motor vehicles than there are Porsche 911's.)

You can continue to climb up the conceptual (intangible) chain of types, too: above motor vehicle there might be "machine" (motor vehicle's are types of machines); then "man-made construct" might be the next type higher; then maybe just "thing", at which we've arrived at the root type of everything in the universe.

When you walk down a busy street, you will be able to identify instances of cars by their type, but you won't ever see a real thing that is that type. Types are defined by a collection of properties, and not by a tangible object in and of itself.

This differs when you walk down a busy page of code! Here you can see the type, just as you can see the instances. The types are called "classes" in Python.

Example

1 class SomeKindOfThing(object):
2
3     def __init__(self, x, y):  # properties
4
5         self.x = x
6         self.y = y
7
8     def compute(self, z):  # an ability
9
10        return self.x * z + self.y

Line 1

class SomeKindOfThing(object):

class is a Python keyword used to start the definition of a new class. SomeKindOfThing is an arbitrary name that this particular class is given. All classes must have a name. (object), after the class name, is a list of yet further classes or types that this class is a type of. In this case, SomeKindOfThing "inherits" from object. object is SomeKindOfThing's super type (the type above it), and SomeKindOfThing is a sub type of object (a type below it).

object

object is the root, universal type in Python. Everything in Python is an object. In the illustration above I'd mentioned that "thing" was the root type of everything in the universe (that it contains within its defintion all things). In Python, this "thing" type is object.

Python has a builtin function called isinstance of this form:

isinstance(a, b) => {True | False}

You call it to check if a is an instance of b. Knowing that everything in Python is an object:

isinstance(SomeKindOfThing, object)     # True
isinstance(1, object)                   # True
isinstance("hello", object)             # True

Oh, and this too:

isinstance(object, object)              # True

(That's one way to solve infinite regress.) If you go back out to the street and look at the stuff, you too can continue to climb the type chain all the way up. You'll get to "thing", and then ask "well, what type of thing are things?". There are lots of answers, and that way lies metaphysics.

When you define a new class, you specify that you are doing so with the class keyword, followed by an arbitrary name, followed by a list of types (or classes) that place this class into the type (or class) hierarchy.

Creating An Instance

When programming, you generally do not use a class itself. Rather, you use instances of a class. This is clear with numbers: you don't use some notional thing called Number when you do calculations - you use instances of Number {1, 2, 3, ...}.

In Python you can create an instance of SomeKindOfThing like so:

instance1 = SomeKindOfThing(7, 8)

And then you can use it:

instance1.compute(2)                    # 22

Lines 3-6

def __init__(self, x, y):

    self.x = x
    self.y = y

This is a method called __init__. A method is a function defined on a class. When an instance is created, the method is bound to the instance. What "bound" means in practice is that, whenever the method is called, the first argument to that method will always be a reference to that instance. In Python the convention is to always name this argument self.

When you do this:

instance1 = SomeKindOfThing(7, 8)
  • an instance i of the class SomeKindOfThing is created
  • the __init__ method is called with these arguments: i, 7, 8

Within the body of the method, we receive i in the self parameter, and 7 and 8 in the x and y parameters respectively.

The self.x = x line assigns the value of x to a property on self called "x". :) So the same for self.y = y.

You can verify this like so:

instance1.x                             # 7
instance1.y                             # 8

In object-oriented parlance, we can say that x and y are properties of the SomeKindOfThing class, and that, for this particular instance instance1, the value of those properties is 7 and 8.

What are classes made of?

One or both of the following:

  • data
  • logic (code, computations, calculations, abilities, etc.)

So far we have seen the data contained by the SomeKindOfThing class. It also has logic. (Strictly speaking we have seen logic, too, since the special __init__ method was called and executed in order to assign the values for the x and y properties to the instance being created.)

Lines 8-10

def compute(self, z):

    return self.x * z + self.y

This method compute is bound to the instance, just like __init__. So when it is called, the instance will be passed in as the first argument (without you ever having to do so), and received as the self parameter:

instance1.compute(2)

2 is received by the z parameter, and the self parameter is instance1.

Why?

Why have object-oriented constructs like this to begin with? What is the point?

If you are programming in a domain that needs to model the world about you, then the object-oriented style corresponds well to the task at hand. It fits. It is an abstraction, to be sure, and so hits limit, but it has sufficient correspondence to a form of hierarchy that seems to actually exist in the real world. It's easy to think about simulating the world as a series of objects, since many of us seem to be doing that already (consciously or otherwise).

The object-oriented style has literally nothing in common, however, with the nature of computation. It does not afford with algorithmic thinking, data structures, math, time/space complexities, etc. That's because those things aren't walking down a busy street - they're not standing there beside the lamp post, or chasing after birds.

Best domains for OO-style programming: games, simulations, user interfaces, and frameworks. Or, anything that interacts with a human.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment