<jupyter_start><jupyter_text>Objektuak eta Klaseak * Klaseek objektu motak errepresentatzen dituzte* Klaseek objektuen egitura definitzen dute:   * Informazio bat baina gehiago bildu   * Berezkoa dituen akzioak definitu   * Eremu/atributu eta funtzioen bidez adierazi  Adibide bat: Point (bi dimentsiotako puntua) * Bi aldagai erabil genitzake, `x` eta `y`   * Aldagai bakarra egokiago<jupyter_code>x = 5.4
y = 1.8
print(f'Point: ({x},{y})')<jupyter_output><empty_output><jupyter_text>* Bikote bat erabil genezake   * Berezko akziorik ez (nKote bat da)<jupyter_code>p = (5.4,1.8)
print(f'Point: ({p[0]},{p[1]})')<jupyter_output><empty_output><jupyter_text>* Point datu mota sor dezakegu   * Aldagai bakarrez adierazi   * Berezko akzio guztiak definitzeko aukera Klasearen definizioa:<jupyter_code>class Point(object):
    """A 2-dimensional point"""
help(Point)<jupyter_output><empty_output><jupyter_text>`Point` izeneko klase bat sortzean, `Point` *klase objektu* berezia sortzen da.   * Klase objektuak exekutagarriak dira      * Klase horretako objektu berriak sortu Point motako objektuak sortzen...<jupyter_code>p = Point()
print(p)<jupyter_output><empty_output><jupyter_text>Objektu batetan eremuak sor daitezke.   * Eremuak beste objektuen erreferentziak dira.   * Aldagaiak balira bezela<jupyter_code>p = Point()
p.x = 5.4
p.y = 1.8
print(f'Point: ({p.x},{p.y})')<jupyter_output><empty_output><jupyter_text>* Objektu berri bat sortzen denean, bere funtzio eraikitzailea exekutatzen da: `__init__()`* Objektuaren eremuak hasieratzeko erabili ohi da* Klasea definitzean, objektuak izango dituen funtzioak defini daitezke<jupyter_code>class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y
p = Point(5.4,1.8)
print(f'Point: ({p.x},{p.y})')<jupyter_output><empty_output><jupyter_text>* `__init__(self,x,y)`-eko lehenengo argumentua, `self`, **berezia da**   * Sortu berri den `Point` objektuaren erreferentzia da, `__init__` funtzioak hasieratuko duena.   * Izenak berdin dio... baina pythoneko programazio estiloan beti `self` erabiltzen da.* `Point(5.4,1.8)` funtzioko 2 argumentuak `__init__(self,x,y)`-en argumentu bilakatzen dira (2. eta 3.)<jupyter_code>class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y
        
p = Point(5.4,1.8)<jupyter_output><empty_output><jupyter_text>Objektuen berezko akzioak definitzen * Klaseen barnean funtzioak sor ditzakegu* Objektu erreferentziak erabil ditzakegu funtzioak exekutatzeko:```pythonz = list("aeiou")z.append(123)p = Point(5.4,1.8)p.funtzio_izena(argumentuak...)``` Puntu baten testu errepresentazioa bueltatzen duen funtzio bat izatea interesgarria litzateke, adibidez:$$ p = Point(3,8) \;\; \Rightarrow \;\; p.str() \;\equiv\; "(3,8)" $$<jupyter_code>from math import sqrt

class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y
        
    def str(self):
        return f'({self.x},{self.y})'
p = Point(3,8)
print(p.str())<jupyter_output><empty_output><jupyter_text>```python    def str(self):        return f'({self.x},{self.y})'    p.str()```* Funtzioak `self` argumentu berezia du* Funtzioa `p` objektuaren bidez exekutatzean, argumentu bat gutxiago* `p.str()`  $\equiv$  `Point.str(p)`* `p.funtzio_izena(a,b,c,d,e)`  $\equiv$  `Point.funtzio_izena(p,a,b,c,d,e)`<jupyter_code>print(p.str(),Point.str(p))<jupyter_output><empty_output><jupyter_text>Puntu baten *modulua* ondoko moduan defini dezakegu:$$ |p| \; = \; \sqrt{(x_p)^2 + (y_p)^2} $$<jupyter_code>from math import sqrt

class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y
    
    def str(self):
        return f'({self.x},{self.y})'
    
    def mod(self):
        return sqrt(self.x*self.x + self.y*self.y)
p = Point(5.4,1.8)
print(p.mod())<jupyter_output><empty_output><jupyter_text>Bi punturen batuketa eta kenketa ere defini ditzakegu:$$ p + q \; \equiv \; (x_p+x_q) \;,\; (y_p+y_q) $$$$ p - q \; \equiv \; (x_p-x_q) \;,\; (y_p-y_q) $$ &rarr; Funtzio hauen argumentua beste puntu bat izango da.&rarr; Funtzio hauek puntu berriak bueltatzen dituzte.<jupyter_code>from math import sqrt

class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def str(self):
        return f'({self.x},{self.y})'

    def mod(self):
        return sqrt(self.x*self.x + self.y*self.y)
    
    def add(self,other):
        return Point(self.x + other.x , self.y + other.y)
    
    def sub(self,other):
        return Point(self.x - other.x , self.y - other.y)
p = Point(1,2)
q = Point(3,5)
x = p.add(q)
y = p.sub(q)
print(f'{p.str()} + {q.str()} = {x.str()}')
print(f'{p.str()} - {q.str()} = {y.str()}')<jupyter_output><empty_output><jupyter_text>Baina... orain arte egin dugunarekin* Sortutako funtzioak esplizituki erabili beharko ditugu<jupyter_code>print(p.str())
print(p)<jupyter_output><empty_output><jupyter_text>* Python-eko eragileen konportamoldea ez da "*zuzena*" izango<jupyter_code>#p + q - p<jupyter_output><empty_output><jupyter_text>Funtzio/Metodo bereziak I - *built-in* funtzioak * Buntzio berezi bat, aurrez erabakitako izena duen klase-funtzioa besterik ez da.   * `__init__(...)` * Built-in funtzio batzuek objektuen funtzio bereziak erabiliko dituzte:   * `str()` &rarr; `__str__()`   * `repr()` &rarr; `__repr__()`   * `len()` &rarr; `__len__()`* Funtzio hauek esistitzen ez badira:   * built-in funtzio batzuek errore bat sortuko dute   * besteak nolabait emaitza bat ematen saiatuko dira.  `str()` &rarr; `__str__()`<jupyter_code>class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def str(self):
        return f'({self.x},{self.y})'<jupyter_output><empty_output><jupyter_text>Orain arteko  klasea ez zegoen `str` funtzioarekin _"konektatua"_.* Objektuak `__str__` funtzio bat definitua badu, `str`-k hori exekutatuko du.* Ez badu, mezu generiko bat bueltatuko du<jupyter_code>p = Point(5.4,1.8)
str(p)<jupyter_output><empty_output><jupyter_text>`__str__`funtzioa definitzen badugu, ordea:<jupyter_code>class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'<jupyter_output><empty_output><jupyter_text>Hemendik aurrera, `str` funtzioa erabili ahal izango dugu<jupyter_code>p = Point(5.4,1.8)
str(p)<jupyter_output><empty_output><jupyter_text>Gainera, beste funtzio batzuk ere, `str` funtzioa erabiliko dute...<jupyter_code>print(p)<jupyter_output><empty_output><jupyter_text>Dena den, honekin ez dugu dena ebatzi:<jupyter_code>z = [1 , 'kaixo' , p]
print(z)<jupyter_output><empty_output><jupyter_text>* Zerrenden `__str__` funtzioak, `repr` funtzioa exekutatzen du elementu bakoitzaren gain.* Bestela ez genituzke komatxoak ikusiko `kaixo`-ren inguruan Esandakoaren froga:<jupyter_code>z = [1 , 'kaixo' , p]
print(z)
print(f'[{", ".join(repr(x) for x in z)}]')
print(f'[{", ".join(str(x) for x in z)}]')<jupyter_output><empty_output><jupyter_text>`repr()` &rarr; `__repr__()`* **Gogoratu:** `repr` &harr; `eval`* Puntua sortzeko `Point(5.4,1.8)` espresioa erabiltzen badugu...   * Hori bera da `repr`-ek bueltatu beharko lukeena<jupyter_code>class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'
    
    def __repr__(self):
        return f'Point({self.x},{self.y})'
p = Point(5.4,1.8)
print(str(p))
print(repr(p))<jupyter_output><empty_output><jupyter_text>`repr` &harr; `eval` propietatea betetzen da:<jupyter_code>q = eval(repr(p))
print(p,q)<jupyter_output><empty_output><jupyter_text>`len()` &rarr; `__len__()`* Esan bezala, built-in funtzio batzuk errore bat sortuko dute dagokien funtzioa topatzen ez badute<jupyter_code># Errore bat gertatuko da... 
#len(p)<jupyter_output><empty_output><jupyter_text>Gure `Point` klasean* Luzerarik gabe utzi genezake* Luzera eta modulua sinonimotzat har genitzake<jupyter_code>from math import sqrt

class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'
    
    def __repr__(self):
        return f'Point({self.x},{self.y})'

    def mod(self):
        return sqrt(self.x*self.x + self.y*self.y)

    def __len__(self):
        return self.mod()
p = Point(5.4,1.8)
# __len__ funtzioa sortu badugu ere, errore bat gertatuko da... 
#print(p,'puntuaren luzera:',len(p))<jupyter_output><empty_output><jupyter_text>`__len__`funtzioak zenbaki oso bat bueltatu behar du, beraz azken aldaketa hau gaizki dago.  Funtzio/Metodo bereziak II - Eragileak Aurreko atalean, `repr` &harr; `eval` erlazioa ebatzi dugu:<jupyter_code>p = Point(5.4,1.8)
q = eval(repr(p))
print(p,repr(p),q)<jupyter_output><empty_output><jupyter_text>Baina `p` eta `q` puntuak berdinak ote dira?<jupyter_code>print(p, q, p==q, p is q)<jupyter_output><empty_output><jupyter_text>* `==` eragileak ez daki ezertxo ere gure `Point` klaseaz* Guk adierazi beharko dugu bi objektu noiz diren berdinak * Python-eko edozein eragile erabiltzean, objektuen funtzio bereziak exekutatzen dira   * Konparazio eragileak: `` `>=`  `==` `!=`   * Eragile aritmetikoak: `+` `-` `*` `/` `//` `%`   * Eragile monadikoak (eragigai bakarra): `+` `-`   * Indexazioa: `obj[key]`   * esleipen indexatua: `obj[key] = ...`   * ezabatze indexatua: `del obj[key]`   * *kidetasun* eragileak: `in` `not in`  Konparazio eragileak: `` `>=`  `==` `!=`* `a < b` &rarr; `a.__lt__(b)`* `a <= b` &rarr; `a.__le__(b)`* `a > b` &rarr; `a.__gt__(b)`* `a >= b` &rarr; `a.__ge__(b)`* `a == b` &rarr; `a.__eq__(b)`* `a != b` &rarr; `a.__ne__(b)` Funtzio hauek sortu ezean, eragileek (batzuk) erroreak sortuko dituzte:<jupyter_code>a = Point(1,2)
b = Point(1,2)
print(f'{a} == {b} : {a==b}')
print(f'{a} == {a} : {a==a}')
print(f'{a} != {b} : {a!=b}')
print(f'{a} != {a} : {a!=a}')
# honek errore bat sortuko du
#print(f'a > b : {a>b}')<jupyter_output><empty_output><jupyter_text>* `a == b` , $ \;\; \nexists \_\_eq\_\_\;$ &rarr; `a is b` * `a != b` , $ \;\; \nexists \_\_ne\_\_\;$ &rarr; `a is not b`* &rarr; `Point` klasean, ardatzeko balioak erabil genitzake puntuak konparatzeko...* &rarr; `Point` klasean, puntuen modulua erabil genezake puntuak konparatzeko...<jupyter_code>class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'
    
    def __repr__(self):
        return f'Point({self.x},{self.y})'

    def mod(self):
        return sqrt(self.x*self.x + self.y*self.y)
    
    def __eq__(self,other):
        return self.x == other.x and self.y == other.y
    def __ne__(self,other):
        return self.x != other.x or self.y != other.y
    
    def __gt__(self,other):
        return self.mod() > other.mod()
    def __ge__(self,other):
        return self.mod() >= other.mod()
    def __lt__(self,other):
        return self.mod() < other.mod()    
    def __le__(self,other):
        return self.mod() <= other.mod()<jupyter_output><empty_output><jupyter_text>Orain, bai:<jupyter_code>p = Point(1,2)
q = Point(3,4)

print(f'{p} == {q} : {p==q}')
print(f'{p} != {q} : {p!=q}')
print(f'{p} > {q} : {p>q}')
print(f'{p} >= {q} : {p>=q}')
print(f'{p} < {q} : {p<q}')
print(f'{p} <= {q} : {p<=q}')<jupyter_output><empty_output><jupyter_text>Eragile aritmetikoak: `+` `-` `*` `/` `//` `%`* `a + b` &rarr; `a.__add__(b)`* `a - b` &rarr; `a.__sub__(b)`* `a * b` &rarr; `a.__mul__(b)`* `a / b` &rarr; `a.__truediv__(b)`* `a // b` &rarr; `a.__floordiv__(b)`* `a % b` &rarr; `a.__mod__(b)` Batuketa eta kenketa defini ditzakegu:<jupyter_code>class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'
    
    def __add__(self,other):
        return Point(self.x+other.x, self.y+other.y)
    def __sub__(self,other):
        return Point(self.x-other.x, self.y-other.y)
p = Point(1,2)
q = Point(3,5)
print(f'{p} + {q} = {p+q}')
print(f'{p} - {q} = {p-q}')<jupyter_output><empty_output><jupyter_text>Eragile monadikoak (eragigai bakarra): `+` `-`* `+ a` &rarr; `a.__pos__()`* `- a` &rarr; `a.__neg__()`<jupyter_code>class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x}, {self.y})'
    
    def __pos__(self):
        return self
    def __neg__(self):
        return Point(-self.x, -self.y)
p = Point(1,2)
print(f'+{p} = {+p}')
print(f'-{p} = {-p}')<jupyter_output><empty_output><jupyter_text>Indexazioa: `obj[key]`* `a[key]` &rarr; `a.__getitem__(key)` Zentzurik ez badu ere puntu bat indexatzea, funtzioa sortu dezakegu `a[key]` patroia konprobatzeko:<jupyter_code>class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'
    
    def __getitem__(self,key):
        if key == 'x' :
            return self.x
        elif key == 'y' :
            return self.y
        else :
            return None
p = Point(1,2)
print(f'p["x"] = {p["x"]}')
print(f'p["y"] = {p["y"]}')
print(f'p["kk"] = {p["kk"]}')
print(f'p[1] = {p[1]}')<jupyter_output><empty_output><jupyter_text>Esleipen indexatua: `obj[key] = ...`* `a[key] = value` &rarr; `a.__setitem__(key,value)` Berriro ere, ez du zentzu handirik, baina frogatzearren...<jupyter_code>class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'
    
    def __setitem__(self,key,value):
        if key == 'x' :
            self.x = value
        elif key == 'y' :
            self.y = value
        else :
            print(f'??? Puntuko {repr(key)} gakoari {repr(value)} balioa esleitu nahi diozu?')
p = Point(1,2)
print(p)
p["x"] = 100
print(p)
p["y"] = 200
print(p)
p[0] = "kk"<jupyter_output><empty_output><jupyter_text>Ezabatze indexatua: `del obj[key]`* `del a[key]` &rarr; `a.__delitem__(key)` Berriro ere, ez du zentzu handirik, baina frogatzearren...<jupyter_code>class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'
            
    def __delitem__(self,key):
        print(f'??? Puntuko {repr(key)} gakoari dagokion elementua ezabatu nahi duzu?')
p = Point(1,2)
del p["x"]
del p[0]<jupyter_output><empty_output><jupyter_text>*kidetasun* eragileak: `in` `not in`* `value in a` &rarr; `a.__contains__(value)`* `value not in a` &rarr; `not a.__contains__(value)` Berriro ere, ez du zentzu handirik, baina frogatzearren...<jupyter_code>class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'
            
    def __contains__(self,key):
        return True if key == 'x' or key == 'y' else False
p = Point(1,2)
print('x' in p, 'y' in p, 'kk' in p , 1 in p)<jupyter_output><empty_output><jupyter_text>Egindako guztia bilduz<jupyter_code>class Point(object):
    """A 2-dimensional point"""
    
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def mod(self):
        return sqrt(self.x*self.x + self.y*self.y)

    def __str__(self):
        return f'({self.x},{self.y})'  
    
    def __repr__(self):
        return f'Point({self.x},{self.y})'
    
    def __eq__(self,other):
        return self.x == other.x and self.y == other.y
    
    def __ne__(self,other):
        return self.x != other.x or self.y != other.y
    
    def __gt__(self,other):
        return self.mod() > other.mod()
    
    def __ge__(self,other):
        return self.mod() >= other.mod()
    
    def __lt__(self,other):
        return self.mod() < other.mod() 
    
    def __le__(self,other):
        return self.mod() <= other.mod()
    
    def __add__(self,other):
        return Point(self.x+other.x,self.y+other.y)
    
    def __sub__(self,other):
        return Point(self.x-other.x,self.y-other.y)
    
    def __pos__(self):
        return self
    
    def __neg__(self):
        return Point(-self.x,-self.y)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.17501793829227458, 'fraction_numerical': 0.007713465678067448, 'mean_word_length': 3.6940780241369633, 'pattern_counts': {'":': 0, '<': 155, '<?xml version=': 0, '>': 159, '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': '36', 'dir': 'jupyter-structured-clean-dedup', 'id': '22781', 'license': 'MIT', 'n_tokens_mistral': 7187, 'n_tokens_neox': 7106, 'n_words': 1402, 'path': 'Gardenkiak/.ipynb_checkpoints/Klaseak-checkpoint.ipynb', 'repo_name': 'mpenagar/Programazioaren-Oinarriak', 'size': '16724'}