from collections.abc import Mapping, MutableMapping
from collections import UserDict

class MapBase(MutableMapping):
  """Our own abstract base class that includes a nonpublic _Item class."""

  #------------------------------- nested _Item class -------------------------------
  class _Item:
    """Lightweight composite to store key-value pairs as map items."""
    __slots__ = '_key', '_value'

    def __init__(self, k, v):
      self._key = k
      self._value = v

    def __eq__(self, other):               
      return self._key == other._key   # compare items based on their keys

    def __ne__(self, other):
      return not (self == other)       # opposite of __eq__

    def __lt__(self, other):               
      return self._key < other._key    # compare items based on their keys

def count_word_freq(doc):
    freq = {}
    words = [word.lower() for word in doc.split(' ') if word.isalpha()]
    for word in words:
        freq[word] = 1 + freq.get(word, 0)
    
    max_word = ''
    max_count = 0
    for (w, c) in freq.items():
        if c > max_count:
            max_word = w
            max_count = c
    return (max_word, max_count)

# https://docs.python.org/3.7/reference/datamodel.html#emulating-container-types
# https://docs.python.org/3/library/collections.abc.html#collections.abc.Collection
# class MyMapping(Mapping):
class MyMapping(MutableMapping):

    def __init__(self):
        self.seq = {}

    def __delitem__(self):
        return 1

    def __setitem__(self, key, value):
        self.seq[key] = value

    def __str__(self):
        return 'MyMapping: ' + str(self.seq)

    def __getitem__(self, key):
        return self.seq[key]

    def __iter__(self):
        return iter(self.seq)

    def __len__(self):
        return len(self.seq)

if __name__ == '__main__':

    person = MyMapping()
    person['name'] = 'juan'
    person['age'] = 48
    print(person)
    print(person['name'])
    print(person['age'])
    print(len(person))

    for k in person:
        print('key', k)

    # doc = """
    # Hash tables are a type of data structure in which the address or the index value of the data element is generated from a hash function. That makes accessing the data faster as the index value behaves as a key for the data value. In other words Hash table stores key-value pairs but the key is generated through a hashing function. So the search and insertion function of a data element becomes much faster as the key values themselves become the index of the array which stores the data.
    # In Python, the Dictionary data types represent implementation of hash tables. The Keys in the dictionary satisfy the following requirements.
    # The keys of the dictionary are hashable i.e. the are generated by hashing function which generates unique result for each unique value supplied to the hash function.
    # The order of data elements in a dictionary is not fixed.
    # So we see the implementation of hash table by using the dictionary data types as below.
    # """
    # freq = count_word_freq(doc)
    # print(freq)