A trie is a specialized type of tree data structure. When used in the context of a dictionary, each node stores the entire alphabet, and words can be reTRIEved by traversing down a branch part of the tree. The structure of a trie tree is a set of linked tries emanating from a head trie. Each trie contains a set of pointers (child tries), one for each alphabetic value.
The image below gives a representation of how a trie dictionary might store the words peter, piper, picked, peck, pickled, and peppers. For simplicity, most of the child nodes are omitted but the tree hierarchy can be readily seen and how a letter at a given level branches out (e.g p, pe, etc).

What is not clear is how the end of a word is recognized. There are many ways to do this, but for a simple dictionary, it is sufficient to have a flag indicating if the trie represents the end of a word or not. Hence a word proceeds letter by letter from the head trie. As the words are unique, the full path for any individual word is also unique, although paths are shared where common (think how "help" and "helpless" would be represented).
For this challenge, we are going to construct a Trie class which can hold a set of lower case English letter words, together with methods and a function to allow it to be used in a basic way:
load(words) — words is a list of words that will be the initial set for the dictionary. The function should create the trie, load the words then return a pointer to the head trie.update(self, words) — This adds any words in the list words which are not already contained in the dictionary.is_word(self, word) — Returns True if word is in the dictionary, otherwise False.remove(self, word) — Removes word from the dictionary if it's present, otherwise no action.contents(self, start="a", end="z") — Returns a list of all or some of the words in the dictionary in ascending alphabetical order. If the start and/or end is present, only return the words which start with the letters between the start and end inclusive. start and end should be validated to ensure end is not before start; if it is, return the string "End cannot be earlier in the alphabet than start".
If the dictionary is empty, return the string "Dictionary is currently empty".method num_words() — Should return the number of words currently in the dictionary. If the dictionary is empty, return the string "Dictionary is currently empty".d = load(["Peter", "Piper", "picked", "peppers"])
d.contents() ➞ ["peppers", "peter", "picked", "piper"]
d.num_words() ➞ 4
d.remove("peppers")
d.is_word("peppers") ➞ False
Trie.num_words() ➞ 3
d.update(["pineapples"])
d.contents("p","p") ➞ ["peter", "picked", "pineapples", "piper"]
is_word may contain capitals. The word lists input to load and update may also contain duplicates.remove method — if you are removing "hope", for example, you need to be sure you can still access "hopeful" if that's present.