# Python Course

Previous Chapter: Slots
Next Chapter: Road to Metaclasses

## Classes and Class Creation

### New-style vs. old-style Classes

As we have mentioned in earlier chapters, there is a subtlety in Python2, which can be the source of great confusion: The coexistence of old-style and new-style classes

The official Python reference says the following:

"New-style classes were introduced in Python 2.2 to unify classes and types. A new-style class neither more nor less than a user-defined type. If x is an instance of a new-style class, then type(x) is the same as x.class."

The next paragraph informs us about the motivation for introducing new-style classes. They are needed "to provide a unified object model with a full meta-model". They mention as other "immediate benefits" the "ability to subclass most built-in types, or the introduction of 'descriptors', which enable computed properties."

We don't want to dive into all the subtleties of old-style classes. Don't think about it as an option to choose from: There should be only one style for you to use: the new-style class!

There is only a minor syntactic difference, which can easily be overlooked: A class can only be a new-style class, if it inherits from object or from another new-style class. Python 3 only has new-style classes.

    # old-style class
    class A:
        pass
    class B(A):
        pass
    a = A()
    b = B()
    print(type(A), type(B))
    print(type(a), type(b))

After having executed the Python code above we received the following:

    (<type 'classobj'>, <type 'classobj'>)
    (<type 'instance'>, <type 'instance'>)

    # new-style class
    class A(object):
        pass
    class B(A):
        pass
    a = A()
    b = B()
    print(type(A), type(B))
    print(type(a), type(b))

The Python code above returned the following:

    (<type 'type'>, <type 'type'>)
    (<class '__main__.A'>, <class '__main__.B'>)

The topics we discover in the following will only be valid, if you define your classes as new-style classes.

### Behind the scenes: Relationship between Class and type

In this chapter of our tutorial, we will provide you with a deeper insight into the magic happening behind the scenes, when we are defining a class or creating an instance of a class. You may ask yourself: "Do I really have to learn theses additional details on object oriented programming in Python?" Most probably not, or you belong to the few people who design classes at a very advanced level.

First, we will concentrate on the relationship between type and class. When you have defined classes so far, you may have asked yourself, what is happening "behind the lines". We have already seen, that applying "type" to an object returns the class of which the object is an instance of:

    x = [4, 5, 9]
    y = "Hello"
    print(type(x), type(y))

This gets us the following result:

    (<type 'list'>, <type 'str'>)

If you apply tpye on the name of a class itself, you get the class "type" returned.

    print(type(list), type(str))

This gets us the following result:

    (<type 'type'>, <type 'type'>)

This is similar to applying type on type(x) and type(y):

    x = [4, 5, 9]
    y = "Hello"
    print(type(x), type(y))
    print(type(type(x)), type(type(y)))

The above Python code returned the following:

    (<type 'list'>, <type 'str'>)
    (<type 'type'>, <type 'type'>)

A user-defined class (or class object) is an instance of the object named "type", which is itself a class.

So, we can see, that classes are created from type, or in other words: A class is an instance of the class "type". In Python3 there is no difference between "classes" and "types". They are in most cases used as synonyms.

The fact that classes are instances of a class "type" allows us to program metaclasses. We can create classes, which inherit from the class "type". So, a metaclass is a subclass of the class "type".

Instead of only one argument, type can be called with three parameters:

    type(classname, superclasses, attributes_dict)

If type is called with three arguments, it will return a new type object. This provides us with a dynamic form of the class statement.

- "classname" is a string defining the class name and becomes the name attribute;
- "superclasses" is a list or tuple with the superclasses of our class. This list or tuple will become the bases attribute;
- the attributes_dict is a dictionary, functioning as the namespace of our class. It contains the definitions for the class body and it becomes the dict attribute.

Let us have a look at a simple class definition:

    class A(object):
        pass
    x = A()
    print(type(x))

The previous Python code returned the following output:

    <class '__main__.A'>

We can use "type" for the previous class defintion as well:

    A = type("A", (), {})
    x = A()
    print(type(x))

The above code returned the following output:

    <class '__main__.A'>
    {'__doc__': None, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>}

Generally speaking, this means, that we can define a class A with

    type(classname, superclasses, attributedict)

When we call "type", the call method of type is called. The call method runs two other methods: new and init:

    type.__new__(typeclass, classname, superclasses, attributedict)
    type.__init__(cls, classname, superclasses, attributedict)

The new method creates and returns the new class object, and after this the init method initializes the newly created object.

    class Robot(object):
        counter = 0
        def __init__(self, name):
            self.name = name
        def sayHello(self):
            return "Hi, I am " + self.name
    def Rob_init(self, name):
        self.name = name
    Robot2 = type("Robot2",
                  (),
                  {"counter":0,
                   "__init__": Rob_init,
                   "sayHello": lambda self: "Hi, I am " + self.name})
    x = Robot2("Marvin")
    print(x.name)
    print(x.sayHello())
    y = Robot("Marvin")
    print(y.name)
    print(y.sayHello())
    print(x.__dict__)
    print(y.__dict__)

We received the following output:

    Marvin
    Hi, I am Marvin
    Marvin
    Hi, I am Marvin
    {'name': 'Marvin'}
    {'name': 'Marvin'}

The class definitions for Robot and Robot2 are syntactically completely different, but they implement logically the same class.

What Python actually does in the first example, i.e. the "usual way" of defining classes, is the following: Python processes the complete class statement from class Robot to collect the methods and attributes of Robot to add them to the attributes_dict of the type call. So, Python will call type in a similar way than we did in Robot2.

Previous Chapter: Slots
Next Chapter: Road to Metaclasses