Low-Level of Class Creation

PythonPythonBeginner
Practice Now

This tutorial is from open-source community. Access the source code

Introduction

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.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("`Python`")) -.-> python/BasicConceptsGroup(["`Basic Concepts`"]) python(("`Python`")) -.-> python/FunctionsGroup(["`Functions`"]) python(("`Python`")) -.-> python/FileHandlingGroup(["`File Handling`"]) python(("`Python`")) -.-> python/ControlFlowGroup(["`Control Flow`"]) python(("`Python`")) -.-> python/DataStructuresGroup(["`Data Structures`"]) python(("`Python`")) -.-> python/ModulesandPackagesGroup(["`Modules and Packages`"]) python(("`Python`")) -.-> python/ObjectOrientedProgrammingGroup(["`Object-Oriented Programming`"]) python(("`Python`")) -.-> python/ErrorandExceptionHandlingGroup(["`Error and Exception Handling`"]) python(("`Python`")) -.-> python/PythonStandardLibraryGroup(["`Python Standard Library`"]) python/BasicConceptsGroup -.-> python/comments("`Comments`") python/FunctionsGroup -.-> python/keyword_arguments("`Keyword Arguments`") python/FileHandlingGroup -.-> python/with_statement("`Using with Statement`") python/BasicConceptsGroup -.-> python/variables_data_types("`Variables and Data Types`") python/BasicConceptsGroup -.-> python/numeric_types("`Numeric Types`") python/BasicConceptsGroup -.-> python/strings("`Strings`") python/ControlFlowGroup -.-> python/conditional_statements("`Conditional Statements`") python/ControlFlowGroup -.-> python/for_loops("`For Loops`") python/ControlFlowGroup -.-> python/list_comprehensions("`List Comprehensions`") python/DataStructuresGroup -.-> python/lists("`Lists`") python/DataStructuresGroup -.-> python/tuples("`Tuples`") python/DataStructuresGroup -.-> python/dictionaries("`Dictionaries`") python/DataStructuresGroup -.-> python/sets("`Sets`") python/FunctionsGroup -.-> python/function_definition("`Function Definition`") python/FunctionsGroup -.-> python/default_arguments("`Default Arguments`") python/FunctionsGroup -.-> python/lambda_functions("`Lambda Functions`") python/ModulesandPackagesGroup -.-> python/importing_modules("`Importing Modules`") python/ModulesandPackagesGroup -.-> python/using_packages("`Using Packages`") python/ModulesandPackagesGroup -.-> python/standard_libraries("`Common Standard Libraries`") python/ObjectOrientedProgrammingGroup -.-> python/classes_objects("`Classes and Objects`") python/ObjectOrientedProgrammingGroup -.-> python/constructor("`Constructor`") python/ObjectOrientedProgrammingGroup -.-> python/polymorphism("`Polymorphism`") python/ObjectOrientedProgrammingGroup -.-> python/encapsulation("`Encapsulation`") python/ErrorandExceptionHandlingGroup -.-> python/catching_exceptions("`Catching Exceptions`") python/ErrorandExceptionHandlingGroup -.-> python/raising_exceptions("`Raising Exceptions`") python/PythonStandardLibraryGroup -.-> python/data_collections("`Data Collections`") python/BasicConceptsGroup -.-> python/python_shell("`Python Shell`") python/FunctionsGroup -.-> python/build_in_functions("`Build-in Functions`") subgraph Lab Skills python/comments -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/keyword_arguments -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/with_statement -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/variables_data_types -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/numeric_types -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/strings -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/conditional_statements -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/for_loops -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/list_comprehensions -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/lists -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/tuples -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/dictionaries -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/sets -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/function_definition -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/default_arguments -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/lambda_functions -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/importing_modules -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/using_packages -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/standard_libraries -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/classes_objects -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/constructor -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/polymorphism -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/encapsulation -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/catching_exceptions -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/raising_exceptions -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/data_collections -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/python_shell -.-> lab-132517{{"`Low-Level of Class Creation`"}} python/build_in_functions -.-> lab-132517{{"`Low-Level of Class Creation`"}} end

Class creation

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

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.

>>> 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:

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

>>>

Finally, create the Stock class object:

>>> 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.

Typed structures

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

## 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:

>>> 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.

Making a lot of classes

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

## 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:

## 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:

_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).

Summary

Congratulations! You have completed the Low-Level of Class Creation lab. You can practice more labs in LabEx to improve your skills.

Other Python Tutorials you may like