<jupyter_start><jupyter_text>Table of ContentsSession 2: Object-oriented programming (OOP)PreworkLearning Outcomes1) Implement a 2D Vector class with additionCheck for understanding2) Write a GroupBy classStudent Breakout3) Parking Lot4) Implement the Bunch design pattern 5) Create an immutable attribute of a classTakeawaysReflection: List the 3 most important concepts from this session Session 2: Object-oriented programming (OOP)------ PreworkIf you have less experience, check out these- https://realpython.com/python3-object-oriented-programming/- https://realpython.com/learning-paths/object-oriented-programming-oop-python/This material is a little old but covers the fundamentals in an entertaining way:<NAME> - Python’s Class Development Toolkit- https://www.youtube.com/watch?v=HTLu2DFOdTg- https://speakerdeck.com/pyconslides/pythons-class-development-toolkit-by-raymond-hettinger- https://jathanism-event-notes.readthedocs.io/en/latest/pycon_2013/talks/pythons_class_development_toolkit.html Learning Outcomes__By the end of this session, you should be able to__:- Define and apply common Object-oriented programming (OOP) techniques.- Create custom classes in Python. Live Coding - https://repl.it/@brianspiering/session2objectorientedprogramming 1) Implement a 2D Vector class with addition------<jupyter_code>reset -fs
class Vector:

    def __init__(self, x=0, y=0): 
        self.x = x
        self.y = y
v1 = Vector(1, 2)
v1
class Vector:

    def __init__(self, x=0, y=0): 
        self.x = x
        self.y = y

    def __repr__(self):
        class_name = self.__class__.__name__
        return f"{class_name}({self.x}, {self.y})"
v1 = Vector(1, 2)
v1
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2
v3
class Vector:

    def __init__(self, x=0, y=0): 
        self.x = x
        self.y = y
        
    def __add__(self, other): 
        return Vector(self.x+other.x, self.y+other.y)

    def __repr__(self):
        class_name = self.__class__.__name__
        return f"{class_name}({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2
v3<jupyter_output><empty_output><jupyter_text>Source: __[Fluent Python](https://www.amazon.com/Fluent-Python-Concise-Effective-Programming/dp/1491946008)__ by <NAME> Check for understandingWhat OOP concept is `v3 = v1 + v2` an example of?Click here for the solution …Polymorphism    Defining an type specific action for a symbol. 2) Write a GroupBy class----- Something like [Panda's grouby concept](https://pandas.pydata.org/pandas-docs/stable/user_guide/groupby.html)<jupyter_code>reset -fs
# More verbose            
class GroupBy(dict):
    
    def __init__(self, seq):
        for value in seq:
            new = self.setdefault(value, [])
            new.append(value)
            self.new = new

# # Less verbose
# class GroupBy(dict):
    
#     def __init__(self, seq):
#         for value in seq:
#             self.setdefault(value, []).append(value)

assert GroupBy('abracadabra') == {'a': ['a', 'a', 'a', 'a', 'a'],
                                 'b': ['b', 'b'],
                                 'r': ['r', 'r'],
                                 'c': ['c'],
                                 'd': ['d']}
dict.setdefault?<jupyter_output><empty_output><jupyter_text>`collections.defaultdict` is useful for settings defaults before filling the dict`dict.setdefault` is useful for setting defaults while or after filling the dict.[Source](https://stackoverflow.com/questions/3483520/use-cases-for-the-setdefault-dict-method)<jupyter_code>gb = GroupBy('abracadabra')
gb.keys()<jupyter_output><empty_output><jupyter_text>Student Breakout------Create a single repl.it workspace for the group.Work together to create to create the best solutions for prompt 1 and 2.__Improve your code__: 1. For Vector code, how can you display the object in a way that makes sense to people?1. For the GroupBy code, is there a way to use inheritance? (Brian says, "Let Python do the work for you.") 3) Parking Lot------Design a parking lot system for 5th & Mission in San Francisco. We plan to launch then disrupt parking lots across the world!What are the entities involved with a parking lot? For each entity, what are the attributes (nouns)? What do they do (verb)?Start by implementing the system for a single type of spot. For example, handicapped.User story: As a user, I would like to tell the Parking Lot system that I want a handicapped spot. The Parking Lot system give me a unique spot id and make sure no one else can get that same spot.[Source](https://www.educative.io/courses/grokking-the-object-oriented-design-interview/gxM3gRxmr8Z) 1. Individually    - Spend 5 minutes thinking and designing.    - Spend 15 minutes coding.    1. After 15 minutes (or so), we'll form small groups    - Take your best ideas and put into one class.    -----Questions for the small groups:- What are the best data structures to use?- How are exceptions handled?- What is the interface (porcelain) vs implementation (plumbing)?-------Entire Group Reflection: Was the design or implement more difficult?-----<jupyter_code>reset -fs
class ParkingLot:

    def __init__(self, board_id):
        self.board_id = board_id
        self.spot_types = {"handicapped"}
        self.handicapped_free_spots = {934, 342, 345, 435} # Spot ids
        # TODO: Implement other types later

    def find_open_spot(self, spot_type):
        message = ""
        if (spot_type == "handicapped") and (len(self.handicapped_free_spots) > 0):
            spot_id = self.handicapped_free_spots.pop()
            message += f"Park in handicapped spot: {spot_id}"
        else:
            message += "Handicapped is full"
        message += "\n"
        print(message)
pdb = ParkingLot(board_id=999)
pdb.find_open_spot(spot_type="handicapped")<jupyter_output>Park in handicapped spot: 345<jupyter_text>4) Implement the Bunch design pattern -------A dictionary that supports attribute-style access, a la JavaScript.```employee = Bunch(name="<NAME>", position="Senior Engineer")assert set(employee.keys()) == {'name', 'position'}assert employee.name == "<NAME>"assert employee.position == "Senior Engineer"```<jupyter_code>class Bunch(dict):
    "Bunch is a dictionary that supports attribute-style access"
    def __init__(self, **kwargs):
        self.update(kwargs) # Add keyword arguments to dict 
        self.__dict__.update(kwargs) # Allow attribute access
        
employee = Bunch(name="<NAME>", position="Senior Engineer")
assert set(employee.keys()) == {'name', 'position'}
assert employee.name == "<NAME>"
assert employee.position == "Senior Engineer"<jupyter_output><empty_output><jupyter_text>5) Create an immutable attribute of a class-----For example, a Person's class with attribute of Social Security Number<jupyter_code>brian = Person(ssn=555_555_5555)
brian.ssn = 1
class Person:
    def __init__(self, ssn):
        self._ssn = ssn 

    @property
    def ssn(self): # Setup redirection; define read-only attribute
        return self._ssn

brian = Person(ssn=555_555_5555)
brian.ssn # Read-only version

brian._ssn = 0 # Mutable version
assert brian.ssn == 0<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11272727272727273, 'fraction_numerical': 0.018461538461538463, 'mean_word_length': 3.5316856780735106, 'pattern_counts': {'":': 0, '<': 30, '<?xml version=': 0, '>': 31, 'https://': 10, 'lorem ipsum': 0, 'www.': 3, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 5, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '308365', 'license': 'Apache-2.0', 'n_tokens_mistral': 2278, 'n_tokens_neox': 2139, 'n_words': 696, 'path': '02_object_oriented_programming.ipynb', 'repo_name': 'brianspiering/programming_study_group', 'size': '7186'}