<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 <h1>Table of Contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Working-with-Python-Classes" data-toc-modified-id="Working-with-Python-Classes-1"><span class="toc-item-num">1&nbsp;&nbsp;</span>Working with Python Classes</a></span><ul class="toc-item"><li><span><a href="#Public,-Private,-Protected" data-toc-modified-id="Public,-Private,-Protected-1.1"><span class="toc-item-num">1.1&nbsp;&nbsp;</span>Public, Private, Protected</a></span></li><li><span><a href="#Class-Decorators" data-toc-modified-id="Class-Decorators-1.2"><span class="toc-item-num">1.2&nbsp;&nbsp;</span>Class Decorators</a></span><ul class="toc-item"><li><span><a href="#@Property" data-toc-modified-id="@Property-1.2.1"><span class="toc-item-num">1.2.1&nbsp;&nbsp;</span>@Property</a></span></li><li><span><a href="#@classmethod-and-@staticmethod" data-toc-modified-id="@classmethod-and-@staticmethod-1.2.2"><span class="toc-item-num">1.2.2&nbsp;&nbsp;</span>@classmethod and @staticmethod</a></span></li></ul></li></ul></li><li><span><a href="#Reference" data-toc-modified-id="Reference-2"><span class="toc-item-num">2&nbsp;&nbsp;</span>Reference</a></span></li></ul></div>
Step1:  Working with Python Classes
Encapsulation is seen as the bundling of data with the methods that operate on that data. It is often accomplished by providing two kinds of methods for attributes
Step2:  When the Python compiler sees a private attribute, it actually transforms the actual name to _[Class name]__[private attribute name]. However, this still does not prevent the end-user from accessing the attribute. Thus in Python land, it is more common to use public and protected attribute, write proper docstrings and assume that everyone is a consenting adult, i.e. won't do anything with the protected method unless they know what they are doing.
Class Decorators
@property The Pythonic way to introduce attributes is to make them public, and not introduce getters and setters to retrieve or change them.
@classmethod To add additional constructor to the class.
@staticmethod To attach functions to classes so people won't misuse them in wrong places.
@Property
Let's assume one day we decide to make a class that could store the temperature in degree Celsius. The temperature will be a private method, so our end-users won't have direct access to it.
The class will also implement a method to convert the temperature into degree Fahrenheit. And we also want to implement a value constraint to the temperature, so that it cannot go below -273 degree Celsius. One way of doing this is to define a getter and setter interfaces to manipulate it.
Step3:  Instead of that, now the property way. Where we define the @property and the @[attribute name].setter.
Step4:  @classmethod and @staticmethod
@classmethods create alternative constructors for the class. An example of this behavior is there are different ways to construct a dictionary.
Step5:  The cls is critical, as it is an object that holds the class itself. This makes them work with inheritance.
Step6:  The purpose of @staticmethod is to attach functions to classes. We do this to improve the findability of the function and to make sure that people are using the function in the appropriate context.
<ASSISTANT_TASK:>
Python Code:
# code for loading the format for the notebook
import os
# path : store the current path to convert back to it later
path = os.getcwd()
os.chdir(os.path.join('..', 'notebook_format'))
from formats import load_style
load_style(plot_style=False)
os.chdir(path)
# 1. magic to print version
# 2. magic so that the notebook will reload external python modules
%load_ext watermark
%load_ext autoreload 
%autoreload 2
%watermark -a 'Ethen' -d -t -v
Explanation: <h1>Table of Contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Working-with-Python-Classes" data-toc-modified-id="Working-with-Python-Classes-1"><span class="toc-item-num">1&nbsp;&nbsp;</span>Working with Python Classes</a></span><ul class="toc-item"><li><span><a href="#Public,-Private,-Protected" data-toc-modified-id="Public,-Private,-Protected-1.1"><span class="toc-item-num">1.1&nbsp;&nbsp;</span>Public, Private, Protected</a></span></li><li><span><a href="#Class-Decorators" data-toc-modified-id="Class-Decorators-1.2"><span class="toc-item-num">1.2&nbsp;&nbsp;</span>Class Decorators</a></span><ul class="toc-item"><li><span><a href="#@Property" data-toc-modified-id="@Property-1.2.1"><span class="toc-item-num">1.2.1&nbsp;&nbsp;</span>@Property</a></span></li><li><span><a href="#@classmethod-and-@staticmethod" data-toc-modified-id="@classmethod-and-@staticmethod-1.2.2"><span class="toc-item-num">1.2.2&nbsp;&nbsp;</span>@classmethod and @staticmethod</a></span></li></ul></li></ul></li><li><span><a href="#Reference" data-toc-modified-id="Reference-2"><span class="toc-item-num">2&nbsp;&nbsp;</span>Reference</a></span></li></ul></div>
End of explanation
class A:
    
    def __init__(self):
        self.__priv = "I am private"
        self._prot = "I am protected"
        self.pub = "I am public"
x = A()
print(x.pub)
# Whenever we assign or retrieve any object attribute 
# Python searches it in the object's __dict__ dictionary
print(x.__dict__)
Explanation: Working with Python Classes
Encapsulation is seen as the bundling of data with the methods that operate on that data. It is often accomplished by providing two kinds of methods for attributes: The methods for retrieving or accessing the values of attributes are called getter methods. Getter methods do not change the values of attributes, they just return the values. The methods used for changing the values of attributes are called setter methods. 
Public, Private, Protected
There are two ways to restrict the access to class attributes:
protected. First, we can prefix an attribute name with a leading underscore "_". This marks the attribute as protected. It tells users of the class not to use this attribute unless, somebody writes a subclass.
private. Second, we can prefix an attribute name with two leading underscores "__". The attribute is now inaccessible and invisible from outside. It's neither possible to read nor write to those attributes except inside of the class definition itself.
End of explanation
class Celsius:
    
    def __init__(self, temperature = 0):
        self.set_temperature(temperature)
    def to_fahrenheit(self):
        return (self.get_temperature() * 1.8) + 32
    def get_temperature(self):
        return self._temperature
    def set_temperature(self, value):
        if value < -273:
            raise ValueError('Temperature below -273 is not possible')
        
        self._temperature = value
# c = Celsius(-277) # this returns an error
c = Celsius(37)
c.get_temperature()
Explanation: When the Python compiler sees a private attribute, it actually transforms the actual name to _[Class name]__[private attribute name]. However, this still does not prevent the end-user from accessing the attribute. Thus in Python land, it is more common to use public and protected attribute, write proper docstrings and assume that everyone is a consenting adult, i.e. won't do anything with the protected method unless they know what they are doing.
Class Decorators
@property The Pythonic way to introduce attributes is to make them public, and not introduce getters and setters to retrieve or change them.
@classmethod To add additional constructor to the class.
@staticmethod To attach functions to classes so people won't misuse them in wrong places.
@Property
Let's assume one day we decide to make a class that could store the temperature in degree Celsius. The temperature will be a private method, so our end-users won't have direct access to it.
The class will also implement a method to convert the temperature into degree Fahrenheit. And we also want to implement a value constraint to the temperature, so that it cannot go below -273 degree Celsius. One way of doing this is to define a getter and setter interfaces to manipulate it.
End of explanation
class Celsius:
    
    def __init__(self, temperature = 0):
        self._temperature = temperature
    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32
    
    # have access to the value like it is an attribute instead of a method
    @property
    def temperature(self):
        return self._temperature
    
    # like accessing the attribute with an extra layer of error checking
    @temperature.setter
    def temperature(self, value):
        if value < -273:
            raise ValueError('Temperature below -273 is not possible')
        
        print('Setting value')
        self._temperature = value
c = Celsius(37)
# much easier to access then the getter, setter way
print(c.temperature)
# note that you can still access the private attribute
# and violate the temperature checking, 
# but then it's the users fault not yours
c._temperature = -300
print(c._temperature)
# accessing the attribute will return the ValueError error
# c.temperature = -300
Explanation: Instead of that, now the property way. Where we define the @property and the @[attribute name].setter.
End of explanation
print(dict.fromkeys(['raymond', 'rachel', 'mathew']))
import time
class Date:
    # Primary constructor
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
    # Alternate constructor
    @classmethod
    def today(cls):
        t = time.localtime()
        return cls(t.tm_year, t.tm_mon, t.tm_mday)
# Primary
a = Date(2012, 12, 21) 
print(a.__dict__)
# Alternate
b = Date.today() 
print(b.__dict__)
Explanation: @classmethod and @staticmethod
@classmethods create alternative constructors for the class. An example of this behavior is there are different ways to construct a dictionary.
End of explanation
class NewDate(Date):
    pass
# Creates an instance of Date (cls=Date)
c = Date.today()      
print(c.__dict__)
# Creates an instance of NewDate (cls=NewDate)
d = NewDate.today()   
print(d.__dict__)
Explanation: The cls is critical, as it is an object that holds the class itself. This makes them work with inheritance.
End of explanation
class Date:
    # Primary constructor
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
    # Alternate constructor
    @classmethod
    def today(cls):
        t = time.localtime()
        return cls(t.tm_year, t.tm_mon, t.tm_mday)
    
    # the logic belongs with the date class
    @staticmethod
    def show_tomorrow_date():
        t = time.localtime()
        return t.tm_year, t.tm_mon, t.tm_mday + 1
Date.show_tomorrow_date()
Explanation: The purpose of @staticmethod is to attach functions to classes. We do this to improve the findability of the function and to make sure that people are using the function in the appropriate context.
End of explanation
<END_TASK>