<jupyter_start><jupyter_text>Custom Sequence Part 2 Mutable Sequences - operator overloading ---> add, iadd- __getitem__ :-  seq[n] OR seq[i:j] OR seq[i:j:k]- __setitem__- __contains__ that will support 'in' operator- __delitem__ - del__rmul__      - n * seq- append, extend, pop methods implementations<jupyter_code>class MyClass:
    def __init__(self,name):
        self.name = name
    
    def __repr__(self):
        return f'MyClass(name = {self.name})'
    
    def __add__(self, other):
        return MyClass(self.name + other.name)
    
    def __iadd__(self,other):
        self.name += other.name
        return self
    
    def __mul__(self,n):
        return MyClass(self.name * n)
    
    def __rmul__(self,n):
        return self.__mul__(n)
    
    def __imul__(self,n):
        self.name *= n
        return self
    
    def __contains__(self,value):
        return value in self.name
c1 = MyClass('NICK')
c2 = MyClass('You')
print(id(c1))
result = c1+c2
result
c1 += c2
c1, id(c1)
c1 = MyClass('Eric')
id(c1)
result = c1 * 3
result
c1 *= 3
id(c1), c1
c1 = MyClass('Eric')
3 * c1
c1 = MyClass('Eric')
c1 * 3
c1 = MyClass('Eric')
'Eric' in c1
'z' in c1<jupyter_output><empty_output><jupyter_text>Custom Sequences Part 2b<jupyter_code>from collections import namedtuple
Point = namedtuple('Point', ' x y')
p1 = Point(10.5, 3.5)
p1
x, y = p1
x
y
import numbers
isinstance(10, numbers.Number)
isinstance(10,numbers.Real)
isinstance(10+2j,numbers.Real)
class Point:
    def __init__(self,x,y):
        if isinstance(x, numbers.Real) and isinstance(y, numbers.Real):
            self._pt = (x,y)
        else:
            raise TypeError('Point co-ordinates must be real numbers.')
    def __repr__(self):
        return f'Point(x={self._pt[0]},y={self._pt[1]})'
    
    def __len__(self):
        return len(self._pt)
    
    def __getitem__(self,s):
        return self._pt[s]    
p1 = Point(10,2.5)
p1
x,y =p1
x
p2 = Point(*p1)
p2
class Polygon:
    def __init__(self,*pts):
        if pts:
            self._pts = [Point(*i) for i in pts]
        else:
            self._pts = []
    
    def __repr__(self): # Needed to represent our object in more descriptive way not only address
        pts_str = ','.join([str(pt) for pt in self._pts])
        return f'Polygon ({pts_str})'
    
    def __len__(self):
        return len(self._pts)
    
    def __getitem__(self,s):
        return self._pts[s]
    
    def __add__(self,other):
        if isinstance(other,Polygon):
            new_pts = self._pts + other._pts
            return Polygon(*new_pts)
        else:
            raise TypeError('Can only cancatinate with other polygons')
    
    def append(self,pt):
        self._pts.append(Point(*pt))
        
    def insert(self, i, pt):
        self._pts.insert(i,Point(*pt))
    
    def extend(self, pts):
        if isinstance(pts,Polygon):
            self._pts = self._pts + pts._pts
        else:
            points = [Point(*pt) for pt in pts] # for simple tuple points
            
            self._pts += points
    def __iadd__(self,other):
        self.extend(other)
        return self
p = Polygon((0,0), Point(1,2))
p
p1 = Polygon(Point(x=0,y=0),Point(x=1,y=2))
p1
p1[0]
p1+p
print(id(p1))
p1 += p

id(p1)
p1 = p1.__iadd__(p)
p1 = Polygon((0,0),(1,1))
p1, id(p1)
p1 += [(2,3),Point(4,3),(8,9)]
p1, id(p1)
pol1 = Polygon((0,0),(1,2))
pol2 = Polygon((1,1),(3,3))
print(pol1,id(pol1))
print(pol2,id(pol2))
pol1.append([10,10])
print(pol1,id(pol1))
print(pol2,id(pol2))
pol2.insert(1,Point(-1,3))
print(pol2,id(pol2))
pol1.extend(pol2)
print(pol1,id(pol1))
pol1.extend([(9,7), Point(4.5,7)])
pol1, id(pol1)<jupyter_output><empty_output><jupyter_text>Custom Sequences Part2C<jupyter_code>class Polygon:
    def __init__(self,*pts):
        if pts:
            self._pts = [Point(*i) for i in pts]
        else:
            self._pts = []
    
    def __repr__(self): # Needed to represent our object in more descriptive way not only address
        pts_str = ','.join([str(pt) for pt in self._pts])
        return f'Polygon ({pts_str})'
    
    def __len__(self):
        return len(self._pts)
    
    def __getitem__(self,s):
        return self._pts[s]
    
    def __setitem__(self,s,val):
        try:
            rhs = [Point(*pt) for pt in val]
            is_single = False
        except TypeError:
            try:
                rhs = Point(*val)
                is_single =True
            except TypeError:
                raise TypeError('Invalid Point or Itterable')
        if isinstance(s,int) and is_single or (isinstance(s,slice) and not is_single):
            self._pts[s] = rhs
        else:
            raise TypeError('Incompatible index/slice assignment')
    
    def __add__(self,other):
        if isinstance(other,Polygon):
            new_pts = self._pts + other._pts
            return Polygon(*new_pts)
        else:
            raise TypeError('Can only concatenate with other polygons')
    
    def append(self,pt):
        self._pts.append(Point(*pt))
        
    def insert(self, i, pt):
        self._pts.insert(i,Point(*pt))
    
    def extend(self, pts):
        if isinstance(pts,Polygon):
            self._pts = self._pts + pts._pts
        else:
            points = [Point(*pt) for pt in pts] # for simple tuple points
            
            self._pts += points
    def __iadd__(self,other):
        self.extend(other)
        return self
    
    def __delitem__(self,s):
        del self._pts[s]
    
    def pop(self,i):
        self._pts.pop(i)
        
    def clear(self):
        self._pts.clear()
p = Polygon((0,0),(1,1),(2,2))
p[0:2]
p[0:2] = [Point(1,2),(10,10),(2.5,2.5)]
p
p[0] = Point(10,20)
p
p[0] = (-1,-1)
p
p[0:2] = Point(20,20)
p[0] = [Point(10,10),Point(20,20)]
del p[0]
p
p.pop(0)
p
p.clear()
p<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.14177953025887194, 'fraction_numerical': 0.030173152751585806, 'mean_word_length': 2.4156908665105385, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '522934', 'license': 'MIT', 'n_tokens_mistral': 2183, 'n_tokens_neox': 2128, 'n_words': 487, 'path': 'Sequence_Project_Implementation.ipynb', 'repo_name': 'nikgun1984/Python-Programming-Part-2', 'size': '5833'}