Optimisation suggestions for Min Heap
Docstrings with every method: Way to go, document MinHeap, too and revisit PEP257 for details.
Your MinHeap tackles the same task as module heapq using much the same strategy, and you express dissatisfaction with run time - a side by side comparison:


in many places, you compute something like node_number or parent_node to repeatedly index __items - not using that variable, but something like parent_node - 1
(Code the way you think about it: if there are multiple places where you want the element at index i-1, write a[i-1], b[i-1]…, if you think same index happening to be i-1, write j = i-1, a[j], b[j]…)
(An optimising compiler can be expected to eliminate common sub-expressions; that is more difficult for an interpreter to justify (and I seem to remember why it might be hard for python).)
insert() assigns the new value to every candidate position, while heapq._siftdown()/heappush() just moves down items of lesser priority and puts the new item once/twice.
extract_min() swaps the items at both ends instead of just replacing the top priority item (see heapq.heappop())
heapify() conditionally assigns None to left_child and right_child to go on and conditionally execute statements comparing these values to None (using != instead of is&amp;not)


heapq._siftup() uses the realistic approach of not comparing values "on the way down": half the nodes are leaf nodes, it is much more likely that the new item will end up near the bottom of the heap.

heapq introduces heappushpop() as a "Fast version of a heappush followed by a heappop."


You seem to be bent on thinking of nodes numbered starting from 1 - nothing wrong with that, and coding the way you think about a solution/problem is the only sane way to start:
for a shot from the hip, allocate one more array element, don't use index 0 and drop all of "the&nbsp;- 1".