Sinif və nümayəndə dəyişənləri

Daha öncə qeyd etdik ki, sahələr, yəni dəyişənlər həm siniflərə, həm də nümayəndələrə aid ola bilər. Sinif daxilində, lakin metod xaricində elan olunan dəyişənlər sinif dəyişənləri, metod daxilində elan olunanlar isə nümayəndə dəyişənləridir.

Gəlin konkret misal üzərində sinif və nümayəndə dəyişənlərini nəzərdən keçirək:

class Personal(): 
    count=0
    def __init__(self, name, pos): 
        self.name = name
        self.pos = pos
        print("{0} {1} vəzifəsinə qəbul
             edildi".format(self.name, self.pos))
        Personal.count += 1

p1 = Personal("Kərim Tahiroğlu", "müdir") 
print("Personal sayı: {0}".format(Personal.count))
p2 = Personal("Murad Talıblı", "menecer") 
print("Personal sayı: {0}".format(Personal.count)) 
print()
print("Müəssisədə vəzifələr:")
print(p1.pos)
print(p2.pos)
print()
print("Müəssisənin personalı:")
print(p1.name)
print(p2.name)

Gördüyünüz kimi burada count sinif dəyişənidir və ona sinif adını (indiki halda Personal) qeyd etməklə müraciət olunur. Bu dəyişən elan olunarkən qiyməti sıfır olaraq təyin edilir, konstruktor işə düşəndə isə bir vahid artırılır. Bundan başqa biz __init__() metodu daxilində iki dənə nümayəndə dəyişənini (self.name və self.pos) elan edirik. Bu dəyişənlərin önündə self parametrinin olması onların nümayəndəyə aid olduqlarını bildirir. Konstruktorun başlığında eyni adlı name və pos parametrləri olsa da Python onları qarışdırmır, Siz də qarışdırmayın 🙂 Nümayəndə dəyişənlərinə müraciət önlərinə obyektin adı (indiki halda p1 və p2) yazılmaqla həyata keçirilir.

ascii() funksiyası

  ascii() funksiyası verilmiş obyekti (sətir, siyahı, kortej və s.) çap ediləbilən sətir şəklində qaytarır. Bu zaman qeyri-ASCII simvollar \x, \u və ya \U çıxışları vasitəsilə ekranlaşdırılır.

Funksiyanın sintaksisi aşağıdakı kimidir:

ascii(object)

   Burada object sətir, siyahı, kortej və s. tipdə ola bilər.

Aşağıda ascii() funksiyasının istifadəsi ilə bağlı nümunələr verilmişdir:

>>> print(ascii("Azərbaycan"))
'Az\u0259rbaycan'
>>> print(ascii("Odlar Yurdu"))
'Odlar Yurdu'
>>> 

   Birinci misaldaki sətirdə ə hərfi qeyri-ASCII simvol olduğuna görə u0259 ilə əvəz edilir.

__init__() metodu

   Siniflər üçün təyin edilən metodlar içərisində xüsusi əhəmiyətə malik __init__() adlı bir metod var. Bu metod sinfin nümayəndəsi (obyekt) meydana gətirildikdən sonra işə düşür. Müxtəlif növ inisiallaşdırmalar (başlanğıc qiymətlərin verilməsi və ilkin əməliyyatlar) üçün __init__() metodunun istifadəsi çox faydalıdır. Ədəbiyyatda __init__() metoduna konstruktor da deyilir.

   Aşağıdakı nümunəni nəzərdən keçirin:

class Kvadrat:
    adef="Kvadrat - bütün tərəfləri bərabər olan
         dördbucaqlıdır." 
    def __init__(self):
        print(Kvadrat.adef) 
    def k_perim(self, a):
        return 4*a
    def k_area(self, a):
        return a*a

kv = Kvadrat()

   Biz burada Kvadrat sinfini elan etdikdən sonra bu sinfin kv nümayəndəsini meydana gətiririk. Sözü gedən obyektin meydana gəlməsindən sonra da __init__() metodu işə düşür. Nəticədə bu metodda nəzərdə tutulmuş əməliyat icra olunur:

>>>
Kvadrat - bütün tərəfləri bərabər olan dördbucaqlıdır. 
>>>

   Gördüyünüz kimi burada __init__() metoduna self parametrini saymasaq heç bir arqument ötürülmür. Lakin zərurət olduqda konstruktor əlavə parametrlərlə də təyin edilə bilər:

class Kvadrat:
    adef="Kvadrat - bütün tərəfləri bərabər olan 
          dördbucaqlıdır." 
    def __init__(self, name):
        print(Kvadrat.adef)
        print("{0} kvadratı".format(name)) 
    def k_perim(self, a):
        return 4*a
    def k_area(self, a):
        return a*a

kv1 = Kvadrat("ABCD")
kv2 = Kvadrat("EFGH")

   Yuxarıdakı proqram kodunda Kvadrat sinfinin __init__() metodunu elan edərkən self ilə yanaşı name parametrini də təyin edirik. Sonra bu sinfin kv1kv2 adlı iki ayrı obyektlərini meydana gətiririk. Daha öncə obyektləri meydana gətirərkən biz arqumentlərdən istifadə etmirdik. İndi isə diqqət etdinizsə, kv1kv2 nümayəndələri üçün sinif adından sonra mötərizə daxilində arqument kimi müvafiq olaraq “ABCD”“EFGH” qiymətlərini verdik. Bu qiymətlər hər bir nümayəndə üçün __init__() metodunun name parametrinə ötürülür. Beləliklə hər bir obyektin inisiallaşdırılması zamanı konstruktora göndərilən arqumentlərdə öz qiymətləri yer alır. Onu da qeyd edək ki, __init__() metodunda istənilən sayda parametr təyin edilə bilər. Obyekt meydana gətirilərkən arqumentlərin qiymətləri ardıcıl şəkildə bu parametrlərə ötürülür. Gördüyünüz kimi __init__() metodunun tətbiqi siniflər üçün çox böyük əhəmiyət kəsb edir.

Siniflər, Obyektlər, Atrubutlar

   Bu dərsimizdə siniflər, obyektlər və atributlardan bəhs edəcəyik.

Siniflər

Siniflərin elan olunması

   Yeni bir sinif aşağıdakı kimi elan edilir:

class Sinif:
    atributlar

   Burada class açar sözü sinfi təyin etmək üçün istifadə olunur, Sinif isə bu sinfə verilən addır. Sinfin gövdəsində də atributlar, yəni sinifin sahə və metodları elan edilir.

   Gəlin ən sadə formada Kvadrat adlı yeni bir sinif meydana gətirək:

class Kvadrat:
    pass

   Biz burada sinfin gövdəsində hələ heç bir atribut elan etmirik, lakin bu bölməni boş da buraxmaq olmaz. Odur ki, burada pass operatorundan istifadə etdik. Az sonra biz Kvadrat sinfini işə yarar hala gətirəcəyik.

Obyektlər

Nümayəndənin (obyektin) meydana gətirilməsi

  İndi isə Kvadrat sinfinin kv adlı bir nümayəndəsini meydana gətirək:

kv = Kvadrat()

   Gördüyünüz kimi biz Kvadrat sinfinə mənsub kv obyektini düzəltmiş olduq. Buraya qədər izah olunanları IDLE mühitində və ya skriptdə yazaraq nəzərdən keçirin:

>>> class Kvadrat:
        pass

>>> kv = Kvadrat()
>>> type(kv)
<class '__main__.Kvadrat'>
>>> print(kv)
<__main__.Kvadrat object at 0x105600c88> 
>>>

   Yuxarıdakı proqram kodunda Kvadrat sinfi elan edildikdən sonra bu sinifdən olan kv obyekti meydana gətirilir. Bundan sonra yoxlamaq üçün həmin obyektin tipi müəyyən edilir. Ekrana onun __main__ modulunda hazırlanmış Kvadrat sinfinin bir nümayəndəsi olduğu haqda məlumat çıxır. Bundan başqa kv obyektini print() funksiyası ilə çapa verdikdə onun yaddaşdakı ünvanını da görmək mümkündür.

Atributlar

Sahə və metodlar

   Qeyd edildiyi kimi obyekt yönümlü proqramlaşdırma verilənlər və funksionallığı obyekt daxilində birləşdirməyə imkan verir. Sinif elan olunarkən biz onun atributlarını, yəni sahələr (dəyişənlər) və metodlarını (funksiyalar) da təyin edirik. Bu atributlar daha sonra həmin sinfin obyektləri (nümayəndələri) tərəfindən istifadə olunur.

Sinif dəyişəni

   Sinfin bütün nümayəndələri (obyektlər) tərəfindən paylaşılan dəyişən (sahə) sinif dəyişəni adlanır. Sinif dəyişənləri sinif daxilində, lakin sinfin metodları xaricində elan olunurlar.

Nümayəndə dəyişəni

   Metod daxilində elan olunan və yalnız cari nümayəndəyə aid olan dəyişən nümayəndə dəyişəni adlanır.

   Sahələr dəyişənlər kimi onlara qiymət mənsub edilərək elan edilirlər. Metodlar isə funksiyalar kimi təyin olunurlar. Lakin onların adi funksiyalardan fərqi ilk parametrlərinin self adlı parametr olmasıdır. Obyektlər mənsub olduqları sinfin metodlarını çağırarkən self parametrinə hər hansı bir qiymət verilmir. Bunu Python özü edir və self parametri ona müraciət edən konkret nümayəndənin (obyektin) özünü bildirir. Əslində bu parametrə başqa ad da vermək olar, lakin self hər kəs tərəfindən qəbul olunmuş bir addır və ənənəyə sadiq qalmaq məsləhət görülür.

   İndi isə gəlin Kvadrat sinfinə sahə və metodlar əlavə edərək bir az genişləndirək:

class Kvadrat:
    adef = "Kvadrat - bütün tərəfləri 
           bərabər olan dördbucaqlıdır." 
    def k_perim(self, a):
        return 4*a
    def k_area(self, a):
        return a*a 

kv = Kvadrat()

print(Kvadrat.adef)
a = int(input("Kvadratın tərəfini daxil edin: ")) 
print("Kvadratın perimetri:",kv.k_perim(a)) 
print("Kvadratın sahəsi:",kv.k_area(a))

   Gördüyünüz kimi biz əvvəlcə Kvadrat sinfini sahə və metodları ilə bərabər təyin etdik. Bundan sonra bu sinifdən olan kv nümayəndəsini meydana gətirib bu obyekt ilə sinifdəki metodları çağırdıq. Bir məqama diqqət yetirin ki, adef sahəsi burada sinif dəyişənidir. Yuxarıdakı proqram kodunu skriptdə yazıb icra edin və nəticəni nəzərdən keçirin.

   Sinifdə təyin olunan metodlara müraciəti aşağıdakı formada da həyata keçirmək olardı:

print("Kvadratın perimetri:", Kvadrat().k_perim(a))
print("Kvadratın sahəsi:", Kvadrat().k_area(a))

   Biz burada Kvadrat sinfinin metodlarını elə onun özü vasitəsilə çağırmış oluruq.

Obyekt Yönümlü Proqramlaşdırma

   Bizim bura qədər yazdığımız proqramlar funksiyalardan, yəni verilənlər üzərində manipulyasiya edən ifadələr bloklarından ibarət idi. Bu yanaşmaya prosedur yönümlü proqramlaşdırma deyilir. Lakin proqramlaşdırmada daha müasir bir paradiqma da var: obyekt yönümlü proqramlaşdırma (OYP).

Obyekt Yönümlü Proqramlaşdırma

   Bu paradiqma verilənlər və funksionallığı obyekt daxilində birləşdirməyə imkan verir. OYP-da verilənlər və onları emal edən funksiyaların bir araya gətirilərək obyekt daxilində saxlanması, eləcə də kənar müdaxilə və yanlış istifadədən qorunmasına inkapsulyasiya (encapsulation) deyilir.

   Obyekt yönümlü proqramlaşdırmanın iki əsas aspekti var – sinif (class) və obyekt (object). Sinif  mahiyyət etibarilə meydana gətirilən yeni bir tipdir, obyekt isə bu tipdən olan konkret bir nümayəndədir (instance). Bunu sadə misalla izah edək. Məsələn İNSAN sinfi bir tipdir, Hz. Adəm obyekti isə bu tipin bir nümayəndəsidir.

   Obyektlər verilənləri özlərinə aid adi dəyişənlərdə saxlayır. Obyekt və ya siniflərə aid olan dəyişənlər sahələr (fields) adlanır. Bundan başqa obyektlərin funksionallığı da ola bilər, yəni onlar funksiyalara sahib ola bilərlər. Bu cür funksiyalara metodlar deyilir. Sahə və metodlar isə bütövlükdə atributlar adlanır. Obyektə onu digər obyektlərdən fərqləndirən xüsusiyyətlərin verilməsi abstraksiya (abstraction) adlanır.

   Obyekt yönümlü proqramlaşdırmanın üstün cəhətlərindən biri də kodun çoxdəfəlik istifadəsidir. Yəni bir dəfə yazılan proqram kodu daha sonra istənilən qədər istifadə oluna bilər. Lazım gələrsə onun baza əsasında əlavələrlə təkmilləşdirilmiş yeni bir kod da hazırlamaq mümkündür. Obyekt yönümlü proqramlaşdırmada bu məqsədlə varislik (inheritance) mexanizmindən istifadə olunur.

   Varisliyi tətbiq etməklə bir sinifdən onun varislərini (xələflərini) əldə etmək mümkündür. Bu zaman yeni xələf sinfin obyektləri öz atributlarından başqa sələf sinfin atributlarına da malik olurlar. Sələf sinfin atributları xələf sinif daxilində yenidən təyin oluna bilər. Ədəbiyyatda sələf sinfə baza sinfi (base class), xələf sinfə də törəmə sinif (derived class) deyilir.

   Yuxarıda qeyd etdik ki, törəmə siniflər baza sinfinin atributlarını əxz edirlər. Adi qaydada bu mənimsəmə eynilə baş verir. Lakin ehtiyac olarsa, irsən keçən atribut varis sinif daxilində xüsusiləşdirilə bilər. Bu zaman eyni adlı bir metod baza sinfinin obyektləri üçün bir cür, törəmə siniflərin obyektləri üçün isə başqa cür realizasiya olunur. Eyni metodun ayrı-ayrı siniflərdə özünü fərqli göstərməsinə polimorfizm (polymorphism) deyilir.

Fayllar

   İndiyə qədər yazdığımız proqramlarda biz giriş verilənlərini ya proqram daxilində dəyişənlərə mənimsədərək verirdik, ya da klaviaturdan daxil edirdik. Proqramlar da öz növbəsində bu verilənləri emal edib nəticəni bizim üçün ekrana çıxarırdı. Lakin bir çox hallarda giriş və çıxış məlumatlarının fayllarda saxlanılması daha məqsədəuyğun olur. Digər proqramlaşdırma dilləri kimi Python dili də fayllarla işləməyə imkan verir.

   Fayl ilə işləməyə başlamadan öncə onu open() funksiyası ilə açmaq lazımdır:

open(fayl, rejim)

   Burada fayl açılan faylın ünvanı ilə bərabər adı və genişləməsidir. İkinci parametr olan rejim isə faylın hansı məqsədlə açıldığını bildirmək üçündür:

Rejim Təyinatı
r Fayl məlumatların oxunması məqsədilə açılır.
w Fayl məlumatların yazılması məqsədilə açılır. Əgər qeyd edilən adda fayl mövcuddursa, yeni məlumatlar yazılmadan öncə ordakı məlumatlar silinir. Fayl mövcud deyilsə, qeyd edilən adda yeni bir fayl meydana gətirilir.
a Fayl məlumatların əlavə edilməsi məqsədilə açılır. Daxil edilən məlumatlar faylın sonuna əlavə edilir.
r+ Fayl məlumatların həm oxunması, həm də yazılması məqsədilə açılır.
rb Fayl məlumatların oxunması üçün ikilik rejimdə (binary mode) açılır.
wb Fayl məlumatların yazılması üçün ikilik rejimdə (binary mode) açılır. Əgər qeyd edilən adda fayl mövcuddursa, yeni məlumatlar yazılmadan öncə ordakı məlumatlar silinir. Fayl mövcud deyilsə, qeyd edilən adda yeni bir fayl meydana gətirilir.
ab Fayl məlumatların əlavə edilməsi üçün ikilik rejimdə (binary mode) açılır. Daxil edilən məlumatlar faylın sonuna əlavə edilir.
r+b Fayl məlumatların həm oxunması, həm də yazılması üçün ikilik rejimdə (binary mode) açılır.

   Default olaraq fayllar mətn rejimində (text mode) açılır. Bu rejimdə sətrlərin fayldan oxunması və fayla yazılması müəyyən kodlaşdırma (susmaya görə UTF-8) əsasında həyata keçirilir. Əgər fayllar mətn faylları deyilsə, onları ikilik rejimdə (binary mode) açmaq (rb, wb, ab və ya r+b) lazım gəlir.

   Bu zaman oxunan və yazılan məlumatlar ikilik obyektlər olur. Faylın açılması zamanı rejim göstərilməyə də bilər. Belə olan halda rejim default olaraq r qəbul edilir.

   Mətn fayllarındakı sətirlərin sonunu bildirən simvollar müxtəlif platformalarda (əməliyyat sistemlərində) fərqli olur, məsələn, Unix-də \n, Windows-da \r\n. Mətn rejimində fayllardan məlumatlar oxunarkən bütün sətir sonları simvolları default olaraq \n simvoluna çevrilir. Fayllara məlumatların yazılması zamanı isə sətir sonunu bildirən \n simvolu yenidən hər platformaya xas sətir sonluğu simvolları ilə əvəz olunur. Sətir sonları ilə bağlı bu çevrilmələr mətn faylları üçün keçərlidir. Digər fayl tipləri ilə işləyərkən (JPEG və ya EXE kimi) ikilik rejimdən (binary mode) istifadə etməlisiniz.

   İndi isə gəlin aşağıdakı nümunəni nəzərdən keçirək:

f = open('adlar.txt', 'w')

   Əvvəlcə onu qeyd edək ki, open() funksiyasının hər iki parametri (fayl və rejim) dırnaqda (tək və ya qoşa) yazılmalıdır. Bu funksiya bizə fayl obyektini qaytarır. Bundan sonra bu obyektlə daha rahat işləmək üçün biz onu bir dəyişənə (f) mənimsədirik. İndiki halda biz adlar.txt adlı faylı w (yazma) rejimində açırıq. Bu adda fayl kompüterimizin yaddaşında olmadığına görə funksiya əvvəlcə onu meydana gətirəcək və sonra da məlumatların yazılması məqsədilə açacaq.

İfadələr

   İlk dərslərimizdən bu yana biz bir çox yerdə ifadələr anlayışı ilə qarşılaşdıq. Artıq bu terminin tərifini verməyin vaxtı gəlib çatdı. İfadələr, proqramlaşdırma dilində elementar əməli təsvir edən sintaksis vahidlər ardıcıllığıdır.

   İfadələr rolunda qiymətlər, dəyişənlər və əməliyyatlar çıxış edə bilər:

>>> 37 
37
>>> x = 42
>>> x
42
>>> print(x)
42
>>> x + 13
55
>>>

   Yuxarıdakı misallarda 37 qiyməti (birinci sətirdə olan) və x dəyişəni ifadədir. Eyni zamanda x = 42 , print(x)x + 13 əməliyyatları da ifadə sayılır.

   Python-un interaktiv rejimində yazılan ifadələr icra olunur və əgər varsa nəticələri ekrana çıxarılır:

>>> n = 114 
>>> m = 96
>>> a = "Oxu!"
>>> a
'Oxu!'
>>> print(a)
Oxu!
>>> type("Oxu!")
<class 'str'>
>>> 33 + 33 + 33
99
>>>

   Yuxarıdakı misallarda ilk üç sətirdəki ifadələr (mənimsətmə əməliyyatları) sadəcə icra olunur, amma ekrana heçnə çıxmır. Digər sətirlərdəki ifadələrin icrası isə həm də ekrana müvafiq nəticələri çıxarır.

   Burada bir məqama da diqqət yetirmək lazımdır. Belə ki, a dəyişəni bir ifadə olaraq icra olunanda nəticə ekrana tək dırnaq arasında çıxır. Amma biz a dəyişənini print() funksiyası ilə çapa verəndə ekrana çıxan nəticə dırnaqsız olur.

   Gəlin eyni ifadələri skriptdə yazaq və proqram faylını çalışdıraq:

n = 114 
m = 96
a = "Oxu!"
a
print(a)
type("Oxu!")
33 + 33 + 33

   Yuxarıdakı proqram icra olunduqda Python Shell pəncərəsində qarşınıza aşağıdakı mənzərə çıxacaq:

>>>
Oxu!
>>>

   Nə baş verdi? Burada bütün ifadələrin icra olunmasına baxmayaraq yalnız print(a) funksiyasının icrasının nəticəsində ekrana məlumat çıxdı.

   Yekunda ifadələr ilə bağlı bir məsələni də qeyd edək. Python-un interaktiv rejimində ən son ifadənin nəticəsi xüsusi bir dəyişəndə ( _ simvolunda) yadda saxlanılır. Aşağıdakı proqramda buna aid nümunələr verilmişdir:

>>> a = 1.2 
>>> a
1.2
>>> print(_)
1.2
>>> _ + 1
2.2
>>> a = _ 
>>> print(a)
2.2
>>> type(a)
<class 'float'>
print(_)
<class 'float'>
>>>

   Misallardan da gördüyünüz kimi, interpretator ən son ifadənin nəticəsini _ dəyişənində yadda saxlayır.

Rekursiyalar

   Biz artıq bilirik ki, bir funksiya öz daxilində başqa funksiyanı çağıra bilər. Amma bilməmiz gərəkən daha bir şey var: funksiya özü özünü də çağıra bilər. Proqramlaşdırmada funksiyaların özü özünü çağırmasına rekursiya, bu cür funksiyalara da rekursiv funksiyalar deyilir.

   Gəlin verilmiş ədədin faktoriyalını (n!) hesablayan kiçik bir funksiya hazırlayaq. Riyaziyyatdan da bildiyiniz kimi n ədədinin faktorialı 1-dən n-ə qədər (daxil olmaqla) natural ədədlərin hasilinə bərabərdir. Məsələn, 5!=5*4*3*2*1. Və o da məlumdur ki, 1!=1 və 0!=1. Buradan belə bir məntiq yürütmək olur ki, n! hesablamaq üçün n*(n-1)! hesablamalıyıq, yəni 5!=5*4!. Belə olan halda 4! üçün 4*3!, 3! üçün 3*2!, 2! hesablamaq üçün də 2*1! hesablanmalıdır. 1! isə 1-ə bərabər olduğuna görə rekursiya burada bitmiş olur.

   O zaman rekursiv funksiya aşağıdakı kimi olacaq:

>>> def fakt(n):
        if n<=1:
                return 1
        else:
                return n*fakt(n-1)


>>> fakt(5)
120
>>>

   Rekursiv funksiyalardan istifadə edərkən diqqət etmək lazımdır ki, sonsuz rekursiya alınmasın. Adətən sonsuz rekursiyalara gətirib çıxaran aşağıdakı iki səbəb olur:

  1. Rekursiyadan çıxışın düzgün təşkil edilməməsi. Məsələn, yuxarıdakı faktorial funksiyasında if n<=1 şərti verilməsəydi, rekursiya mənfi ədədlərə doğru sonsuz şəkildə davam edərdi.
  2. Rekursiv çağırışda parametrlərin düzgün verilməməsi. Məsələn, əgər fakt(n) funksiyası fakt(n-1) əvəzinə elə fakt(n) funksiyasını çağırsaydı, yenə də sonsuz rekursiya alınardı.

   Gəlin daha bir misal işləyək. Verilmiş a ədədini n qüvvətinə yüksəldən funksiya təyin edək:

>>> def power(a,n):
        if n==1:
                return a
        else:
                return a*power(a,n-1)


>>> power(2,4)
16
>>> power(8,3)
512
>>>

 Biz ən başda qeyd etdik ki, rekursiv funksiyalar özü özünə müraciət edən funksiyalardır. Amma bu müraciətlərin sayı (rekursiyanın dərinliyi) sonsuz ola bilməz. Hətta səhvən sonsuz rekursiya təşkil etsək belə praktiki olaraq funksiya sonsuz sayda icra olunmayacaq. Rekursiyanın dərinliyi ilə bağlı aşağıdakıları bilmək vacibdir:

  1. Rekursiyanın dərinliyinə məhdudiyyət qoyulmuşdur. Default olaraq (susmaya görə) rekursiv funksiya 1000 dəfə özü özünə müraciət edə bilər. 
  2. Bu məhdudiyyət sys.setrecursionlimit() funksiyasından istifadə edilməklə dəyişdirilə bilər. Cari limitə baxmaq üçün isə sys.getrecursionlimit() funksiyası çağırılmalıdır.
  3. Buna baxmayaraq rekursiyanın dərinliyi əməliyyat sistemi tərəfindən təyin olunan stekin ölçüsü ilə məhdudlaşdırılır.

  Son olaraq onu da deyək ki, rekursiv funksiyalar ümumilikdə proqramın məhsuldarlığını azaltdığı üçün onlara yalnız zərurət halında müraciət etmək lazımdır.

Məntiq operatorları

   Yuxarıda qeyd etmişdik ki, nəticəsi doğru (True) və ya yalan (False) olan ifadələr məntiqi ifadələrdir. Biz sadə məntiqi ifadələrdən xüsusi məntiqi birləşdiricilərin köməyilə daha mürəkkəb məntiqi ifadələr əldə edə bilərik. Bu məntiqi birləşdiricilərə məntiq operatorları deyilir. 

   Python proqramlaşdırma dilində məntiq operatorları kimi and (və), or (və ya) və not (deyil) operatorlarındn istifadə olunur. 

   Sadə məntiqi ifadələrin məntiq tipində nəticəsi (qiyməti) olduğu kimi, mürəkkəb məntiqi ifadələrin də məntiqi nəticəsi (qiyməti) vardır. Mürəkkəb məntiqi ifadələrin nəticəsi onu təşkil edən sadə məntiqi ifadələrin nəticələrindən (qiymətlərindən) və bu ifadələri birləşdirən məntiqi birləşdiricilərin növündən, yəni istifadə olunan məntiq operatorundan asılıdır. 

  Gəlin bu dediklərimizi aşağıdakı cədvəllərdə göstərək:

ifadə1 ifadə2 ifadə1  and  ifadə2  ifadə1  or  ifadə2
 False  False  False  False
 False  True  False  True
 True  False  False  True
 True  True  True  True
ifadə not  ifadə
 False  True
 True  False

   Riyaziyyatda bu cədvəllərə doğruluq cədvəlləri deyilir. Birinci cədvəldən də gördüyünüz kimi ifadə1 and ifadə2 mürəkkəb məntiqi ifadəsinin qiyməti yalnız o halda True (doğru) olur ki, onu təşkil edən ifadə1ifadə2 eyni zamanda True qiymətini almış olsun, qalan digər hallarda  isə mürəkkəb məntiqi ifadənin qiyməti False (yalan) olur. 

   Yenə birinci cədvəldən aydın olur ki, ifadə1 or ifadə2 mürəkkəb məntiqi ifadəsinin qiyməti o halda True (doğru) olur ki, onu təşkil edən ifadə1 ifadə2 ifadələrindən heç olmazsa biri True qiymətini almış olsun, qalan yeganə halda (hər ikisi False olduqda)  isə mürəkkəb məntiqi ifadənin qiyməti False (yalan) olur.

   İkinci cədvəldə göstərilən not (məntiqi inkar, deyil) operatoru verilmiş məntiqi ifadənin inkarını əldə etməyə imkan verir. Əgər ifade qiymət olaraq True almışsa, o zaman not ifade bizə False qiymətini verəcək. Eyni qayda ilə əgər ifade qiymət olaraq False almışsa, bu zaman da not ifade bizə True qiymətini verəcək. Burad diqqət yetirsəniz görərsiniz ki, not operatoru yalnız bir ifadə ilə işləyir. Belə operatorlara unar operator deyilir. 

   İndi isə məntiq operatorlarını misallar üzərində nəzərdən keçirək:

>>> a=5
>>> b=10
>>> c=2.5
>>> p="Bakı"
>>> a>3 and b<=15 True >>> p=="Bakı" or p=="bakı"
True
>>> not c==2.5
False
>>>

   Yuxarıdakı misallara bənzər sadə məntiqi ifadələrdən müxtəlif kombinasiyalı mürəkkəb məntiqi ifadələr qurun və proqramını yazaraq sınaqdan keçirin. Alınan nəticələri doğruluq cədvəlləri ilə yoxlayın.

Üzvlük operatorları

   Bir qiymət və ya dəyişənin verilmiş ardıcıllıq (sətir, siyahı və kortej) və ya kolleksiyanın (çoxluq və lüğət) üzvü olub-olmadığını yoxlamaq üçün üzvlük operatorlarından istifadə olunur. Python proqramlaşdırma dilində iki üzvlük operatoru mövcuddur: in (daxildir) və not in (daxil deyil):

Gəlin aşağıdakı misalları nəzərdən keçirək:

>>> s = "Dərbənd"
>>> z= [1, 2, 3]
>>> k= ('a', 'b', 'c', 'd', 'e')
>>> f = "bənd"
>>> n = 4
>>> t = 'g'
>>> f in s
True
>>> n in z
False
>>> t not in k
True
>>>

   Gördüyünüz kimi, əgər dəyişənin aldığı qiymət ardıcıllıqda tapılırsa ifadənin nəticəsi True, əks halda False olur.