\[ [Index](index.md) | [Exercise 7.3](ex7_3.md) | [Exercise 7.5](ex7_5.md) \]

# Exercise 7.4

*Objectives:*

- Learn about the low-level steps involved in creating a class

*Files Modified:* `validate.py`, `structure.py`

In this exercise, we look at the mechanics of how classes are actually
created. 

## (a) Class creation

Recall, from earlier exercises, we defined a simple class
`Stock` that looked like this:

```python
class Stock:
    def __init__(self,name,shares,price):
        self.name = name
        self.shares = shares
        self.price = price
    def cost(self):
        return self.shares*self.price
    def sell(self,nshares):
        self.shares -= nshares
```

What we're going to do here is create the class manually.  Start out
by just defining the methods as normal Python functions.

```python
>>> def __init__(self,name,shares,price):
        self.name = name
        self.shares = shares
        self.price = price

>>> def cost(self):
        return self.shares*self.price

>>> def sell(self,nshares):
        self.shares -= nshares

>>>
```

Next, make a methods dictionary:

```python
>>> methods = {
         '__init__' : __init__,
         'cost' : cost,
         'sell' : sell } 

>>>
```

Finally, create the `Stock` class object:

```python
>>> Stock = type('Stock',(object,),methods)
>>> s = Stock('GOOG',100,490.10)
>>> s.name
'GOOG'
>>> s.cost()
49010.0
>>> s.sell(25)
>>> s.shares
75
>>>
```

Congratulations, you just created a class.   A class is really nothing
more than a name, a tuple of base classes, and a dictionary holding
all of the class contents. `type()` is a constructor that
creates a class for you if you supply these three parts.

## (b) Typed structures

In the `structure.py` file, define the following function:

```python
# structure.py

...
def typed_structure(clsname, **validators):
    cls = type(clsname, (Structure,), validators)
    return cls
```

This function is somewhat similar to the `namedtuple()` function in that it creates a class. Try it out:

```python
>>> from validate import String, PositiveInteger, PositiveFloat
>>> from structure import typed_structure
>>> Stock = typed_structure('Stock', name=String(), shares=PositiveInteger(), price=PositiveFloat())
>>> s = Stock('GOOG', 100, 490.1)
>>> s.name
'GOOG'
>>> s
Stock('GOOG', 100, 490.1)
>>>
```

You might find the seams of your head starting to pull apart about now.

## (c) Making a lot of classes


There are other situations where direct usage of the `type()` constructor might be advantageous.
Consider this bit of code:

```python
# validate.py
...

class Typed(Validator):
    expected_type = object
    @classmethod
    def check(cls, value):
        if not isinstance(value, cls.expected_type):
            raise TypeError(f'expected {cls.expected_type}')
        super().check(value)

class Integer(Typed):
    expected_type = int

class Float(Typed):
    expected_type = float

class String(Typed):
    expected_type = str
...
```

Wow is the last part of that annoying and repetitive.  Change it
to use a table of desired type classes like this:

```python
# validate.py
...

_typed_classes = [
    ('Integer', int),
    ('Float', float),
    ('String', str) ]

globals().update((name, type(name, (Typed,), {'expected_type':ty}))
                 for name, ty in _typed_classes)
```

Now, if you want to have more type classes, you just add them to the
table:

```python
_typed_classes = [
    ('Integer', int),
    ('Float', float),
    ('Complex', complex),
    ('Decimal', decimal.Decimal),
    ('List', list),
    ('Bool', bool),
    ('String', str) ]
```

Admit it, that's kind of cool and saves a lot of typing (at the keyboard).

\[ [Solution](soln7_4.md) | [Index](index.md) | [Exercise 7.3](ex7_3.md) | [Exercise 7.5](ex7_5.md) \]

----
`>>>` Advanced Python Mastery  
`...` A course by [dabeaz](https://www.dabeaz.com)  
`...` Copyright 2007-2023  

![](https://i.creativecommons.org/l/by-sa/4.0/88x31.png). This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)
