# Python-da classlar (Hissə 1): Classlar və obyektlərin yaradılması

Python dilində demək olar ki, hər şey obyektdir. Obyekt sadə şəkildə desək, məlumatların (dəyişənlər) və metodların (ingcə. **method**) birləşməsidir. *Class* da bunlardan biridir. Bəs *class*-ı başqalarından fərqli edən nədir? O elə bir obyektdir ki, başqa obyektlərin yaradılmasında istifadə edilə bilir. 

> “Metod” və “funksiya” sözləri class kontekstində eyni mənanı daşıyır və bu məqalədə “metod” sözünü məhz bu mənada işlədəcəm.

Biz *classı* evin sxeminə bənzədə bilərik. Bu sxemdə ev haqqında bir çox məlumatı (evin ölçülərini, tikilmə təlimatlarını və s.) tapa bilirik. Sxemdə qeyd olunanlara əsasən də evi tikmək olur. Nəticədə bu tikdiyimiz ev obyekt sayılır.

Bir sxemdən bir çox ev tikilə bildiyi kimi, bir classdan da bir neçə obyekt düzəldilə bilər. Hər yaradılan obyekt bu classın instansiyası (ingcə. **instance**) sayılır və bu prosesin adı isə (səhv tərcümə olma ehtimalı çoxdur) instansiasiyadır (ingcə. **instantiation**).

Söz ilə izah etmək kod ilə izah etməkdən daha çətin olacaq, deyəsən … İndi əsas məsələyə keçmək vaxtıdır.

### Classların yaradılması

<script src="https://gist.github.com/khasizadaj/599eb21b93437500546697d72351804f.js"></script>


```python
class Person:
	"""
	This is docstring for Person class. It is empty for now.
	"""
	pass
```

> Kodda əsasən ingilis dilindən istifadə edəcəm. Kodun yazıldğı font bizim dili dəstəkləmədiyi üçün belə etməyə məcbur qaldım. Bununla belə kodun izahını bizim dildə verəcəyəm.

Class yaratmaq üçün dildə rezerv olunmuş sözlərdən biri olan `class` sözünün ardınca yaratmaq istədiyimiz classın adını qeyd edirik. Funksiyalarda olduğu kimi boşluqların (ingcə. **whitespace**) olması önəmlidir. 

Hal hazırda classda heç bir şey qeyd edilməyib və sadəcə komment və `pass` kod hissəciyindən ibarətdir. Başlanğıcda boş olduğuna görə Python-dan xəta mesajı almamaq üçün bu şəkildə yazmaq lazımdır.  İndi isə yeni obyekt yaratmaq haqda danışaq.

### Yeni obyektin yaradılması

<script src="https://gist.github.com/khasizadaj/93eb52571d2c61562f90f5912e7a733f.js"></script>


```python
person_1 = Person()				# creating first Person instance.

person_1.f_name = "Javid" 		# first name 
person_1.l_name = "Khasizada" 	# last name
person_1.age = 21	 			# age

print(person_1.f_name) 			# output: Javid  
```

Classdan istifadə edərək yeni obyekt yaratmaq üçün class adını çağırmaq lazımdır, bu eynilə funksiyanı istifadə etməyə bənzəyir.  1-ci sətirdə biz `person_1` obyektini yaratmışıq. 

Bir əvvəlki bölmədə gördüyümüz kimi class-ın daxilində heç bir məlumat və ya funksiya yoxdur, o səbəbdən 3-5-ci sətirlərdə obyektə yeni dəyişənlər (ingcə. **variable**) əlavə edirik. Bu şəkildə biz adı Cavid, soyadı Xasizadə və yaşı 21 olan `person_1` obyekti əldə edirik. Yaddaşa verilmiş bu məlumatları 7-ci sətirdə göründüyü kimi sonradan çap etmək də mümkündür. 

> Yeri gəlmişkən, Python ilə birlikdə adımın ingiliscə necə olduğunu da öyrənmiş oldun :)

Lakin burda kiçik bir problem var. Hər dəfə yeni obyekt yaradan zaman bu prosesi təkrarlamaq heç də məntiqli səslənmir. Bu səbəbdən də classın bu prosesi daha sərfəli yol ilə həll edən bir metodu var və bu `__init__` metodudur.  Bu metoddan istifadə edərək obyekt yaradılan zaman dəyişənləri obyektin yaddaşına yaza bilərik. 

*Artıq class-ımız boş olmayacaq!*

<script src="https://gist.github.com/khasizadaj/f381145290fdef766723cdc136783f23.js"></script>



```python
class Person:
	"""
	This is docstring for Person class.  
	
	Methods
		__init__: initializes new object and saves provided 
			variables for objects.
	"""
	def __init__(self, f_name, l_name, age):
        self.f_name = f_name            # first name
        self.l_name = l_name            # last name
        self.age = age
        
person_1 = Person("Javid", "Khasizada", 21)

print(person_1.f_name)			        # output: Javid
```

 Gəlin ilk öncə funskiyada olan parametrləri başa düşək. Gördüymüz kimi 4 parametr qeyd olunub və bunlar `self`, `f_name`, `l_name` və `age`-dir. Son 3 parametr bizim bir əvvəki kodda əlavə etmək istədiyimiz məlumatlardır. Birinci parametr isə bəzən çaşqınlığa səbə olan nüanslardan biridir.  

Bu parametr hal-hazırkı obyektin özünə istinad edir. Məsələn, `person_1` obyekti yaranan zaman `self` parametri `person_1`-in özüdür. `self.f_name = f_name` ilə bir az əvvəl yazdığımız `person_1.f_name` eyni əməliyyatı edir. Obyektin yaddaşına bu dəyişəni əlavə edir və sonradan istifadəsinə şərait yaradır. Məhz bu səbəbdən biz 16-ci sətirdə adın çap edildiyini görə bilərik.

 `__init__` funksiyası olduğu zaman obyekt yaradılması nisbətən dəyişir və əlavə etmək istədiyimiz məlumatlar classa arqument kimi ötürülür (14-cü sətir).  Bir də onu qeyd etməliyik ki, `self` parametri üçün heçnə etmək lazım deyil. Avtomatik olaraq bu dil tərəfində həll edilir və obyektin özü arqument kimi metoda ötürülür. 

### Metodlar (funksiyalar)

Classın tərifində dediyimiz kimi class dəyişənlər və metodlardan ibarətdir. Dəyişənlər mövzusuna bir daha geri dönəcək olsaq da, bu hissə haqqında qısaca danışdıq. Metodlara (ingcə. method) gəldikdə isə, onlar elə funksiyadır deyə bilərik. 

Hər yeni obyekt classda olan metodları avtomatik olaraq istifadə edə bilir. Bundan əlavə obyektin məlumatlarını funksiyaya arqument kimi ötürməyə də ehtiyac qalmır. Sözü çox uzatmadan gəlin nümunə üzərindən davam edək.

<script src="https://gist.github.com/khasizadaj/deae29f7e2edff76890041b3041e64d5.js"></script>



```python
class Person:	
	def __init__(self, f_name, l_name, age):
        self.f_name = f_name            # first name
        self.l_name = l_name            # last name
        self.age = age
    
    def get_fullname(self):
        return f'{self.f_name} {self.l_name}' # '{} {}'.format(self.f_name, self.l_name)

person_1 = Person("Javid", "Khasizada", 21)

print(person_1.get_fullname())			# output: Javid Khasizada
```

> *Qeyd:* Artıq bəzi kommentləri gərəksiz olduğu üçün, daha doğrusu, kod açıq-aydın olduğu üçün sildim. Zənnimcə, kömək etmirsə olmasa, daha yaxşıdır.

Artıq `Person` classında yeni metod var, bu metodun əsas məqsədi çağırıldığı zaman insan obyektinin tam adını geri qaytarır. 12-ci sətirdən də görmək olar ki, sadəcə funksiyanı obyektin ardınca çağırmaqla (`object.method_name()`) istifadə etmək olar. `__init__` metodunda olduğu kimi bu metodlda da `self` parametri vacibdir. `self` parametrindən istifadə edərək obyektə əlavə etdiyimiz ad və soyadı qaytara bilərik. 

Biz bu metodlara başqa parametrlər də əlavə edə bilərik. Bunun üçün sadəcə `self`-dən sonra istədiyimiz parametri əlavə edirik.  Deyək ki, insanın hər hansı bir verilən ildə neçə yaşı olduğunu və ya olacağını öyrənmək istəyirik. Bunu aşağıdakı kimi yaza bilərik.

<script src="https://gist.github.com/khasizadaj/4f68f7acb6f1161fff2f973af099bf38.js"></script>




```python
from datetime import datetime

class Person:
	# some code
    
    def calculate_age(self, year):
        """
        Function returns age of person in given year.
        
        Args
        	year: integer
        """
        
        curr_year = datetime.today().year 	# current year
        birth_year = curr_year - self.age

        if birth_year > year:
            return f"I was born in {birth_year}."

        return year - birth_year

person_1 = Person("Javid", "Khasizada", 21)
print(person_1.calculate_age(2015)) 		# output: 15
print(person_1.calculate_age(1987))			# output: I was born in 2000.
```

Nümunələrdən də gördüyümüz kimi istənilən ildə insanın neçə yaşı olduğunu hesablaya bilirik. Əlavə olaraq əgər insan hələ doğulmayıbsa, doğulduğu ili göstərən mesajı cavab kimi qaytarırıq. Bu qədər sadə şəkildə yeni parametrlər əlavə edərək metodlarımızı daha da genişləndirə bilərik.  

### Məzmun

Beləliklə bu məqalənin sonuna çatdıq. Bu məqalədə aşağıdakıları öyrəndik:

* Class və onun yaradılması
* Obyektin yaradılması
* Obyektə məlumatların yazılması
* Metodlardan istifadə


