from math import log2
import numbers
import collections.abc
class Tree(collections.abc.Sequence):
class Node:
def __init__(self,value):
self.left=None
self.right=None
self.value=value
def __init__(self,value):
self.root=Tree.Node(value)
self.len=1
def appendBreathFirst(self,value):
queue=[self.root]
while len(queue)>0:
node=queue.pop(0)
if node.left is None:
node.left=Tree.Node(value)
self.len+=1
return node.left
queue.append(node.left)
if node.right is None:
node.right=Tree.Node(value)
self.len+=1
return node.right
queue.append(node.right)
def getNode(self,key):
if key>=len(self) or key<0:
raise IndexError('Index out of range')
if key==0:
return self.root
row=int(log2(key+1))
currentNode=self.root
for r in range(1,row+1):
k=int((key+1)/2**(row-r)-1)
if k%2 :
currentNode=currentNode.left
else:
currentNode=currentNode.right
return currentNode
def setNode(self,key,node):
row=int(log2(key+1))
currentNode=self.root
for r in range(1,row):
f=2**(row-r)
k=int((key+1- f)/f)
if k%2 :
currentNode=currentNode.left
else:
currentNode=currentNode.right
if key%2 :
currentNode.left=node
else:
currentNode.right=node
def __len__(self):
return self.len
def __getitem__(self,key):
if isinstance(key,slice):
temp=[]
for i in range(0,len(self))[key]:
temp.append(self.getNode(i))
return temp
if isinstance(key,int):
return self.getNode(key)
raise TypeError("invalid index")
def __setitem__(self,key,value):
if isinstance(key,slice) and isinstance(value,list):
for i in range(0,len(self))[key]:
self.getNode(i).value=value.pop(0)
elif isinstance(key,int):
self.getNode(key).value=value
else:
raise TypeError("invalid index or value")
def __imul__(self,m):
if isinstance(m,numbers.Number):
for i in range(0,len(self)):
self.getNode(i).value*= m
return self
def __eq__(self,otherTree):
if not isinstance(otherTree,Tree):
return NotImplemented
if len(self)!=len(otherTree):
return False
for i in range(0,len(self)):
if self.getNode(i).value!=
otherTree.getNode(i).value:
return False
return True
def __hash__(self):
temp=[]
for i in range(0,len(self)):
temp.append(self.getNode(i).value)
return hash(tuple(temp))
Summary
Adding indexing to custom data classes is a matter of defining the __getitem__ and __setitem__ methods.
Extending indexing to slicing is also easy, but actually handling a general slice object is tricky.
Python makes defining operators very easy as each operator has its own __operator__ function that you can redefine.
Two objects that test as equal should return the same hash value.
Making a data class hashable is much easier than you might expect using the supplied __hash__ function on its components.
Python is not strongly-typed and this is mostly good, but there are some drawbacks of the approach.
The idea of Abstract Base Classes (ABC) combined with multiple inheritance provides a facility that is more powerful and logical than abstract single inheritance and interfaces.
Using the abc module and its ability to register an arbitrary class as a subclass of another without involving inheritance is a powerful and useful ability.
The predefined ABC classes, numbers and collections, can help you implement your own data classes.
Although abstract classes provide a way of ensuring that a class has a particular attribute, sometimes it is useful to be able to dynamically add attributes to classes and instances and this is possible using getattr and setattr.
You can also use dynamic attributes to create extension methods, but this doesn’t work on built-in types.