Funksiya arqumentləri

Funksiyalar çağrıldığı zaman onların arqumentləri parametrlərə göndərilir. Biz funksiyaları aşağıdakı növ arqumentlərlə çağıra bilərik:

  • mütləq arqumentlər (required arguments);
  • açar sözlü arqumentlər (keyword arguments);
  • default (susmaya görə) arqumentlər (default arguments);
  • ixtiyari uzunluqlu arqumentlər (variable-length arguments).

İndi də bu arqumentləri bir-bir nəzərdən keçirək.

Mütləq arqumentlər

Funksiya təyin olunarkən ona ötürüləcək arqumentlər müəyyən sayda və ardıcıllıqda göstərilibsə, o, eyni saydakı və ardıcıllıqdakı arqumentlərlə də çağrılmalıdır. Belə arqumentlər mütləq arqumentlər adlanır.
Aşağıdakı proqramda simvolun sətirdə neçə dəfə təkrarlandığını müəyyənləşdirən funksiya və ondan necə istifadə edilməsi verilmişdir:

>>> def cinstr(c, s): 
        n = 0
        for i in s: 
            if c == i:
                n += 1 
        return n

>>> cinstr('a', 'balaban') 
3
>>> cinstr('balaban', 'a') 
0
>>> cinstr('a')
Traceback (most recent call last):
  File "<pyshell#17>", line 1, in <module> 
    cinstr('a')
TypeError: cinstr() missing 1 required positional argument: 's' 
>>>

Proqramdan da göründüyü kimi, ikinci misalda arqumentlərin ardıcıllığı yanlış verildiyinə görə istənilən nəticə əldə olunmur. Üçüncü misalda isə onların sayı əksik olduğundan interpretator xəta qeydə alır.

Açar sözlü arqumentlər

Funksiya çağrılarkən arqumentlərin ixtiyari ardıcıllıqda göstərilə bilməsi üçün onlar parametr adlarından istifadə edilməklə verilməlidir. Bu cür arqumentlər açar sözlü arqumentlər adlanır.
Aşağıdakı proqramda simvol və ya sətri n dəfə təkrarlayan funksiya və ondan istifadə edilməsi göstərilmişdir:

>>> def repstr(s, n): 
        return s * n

>>> repstr(n = 2, s = 'do re mi fa sol lya si ') 
'do re mi fa sol lya si do re mi fa sol lya si ' 
>>>

Gördüyünüz kimi, parametrlərin adından və bərabərlik işarəsindən istifadə etməklə arqumentləri istənilən ardıcıllıqda vermək olar.

Default (susmaya görə) arqumentlər

Funksiya çağrılarkən onun hansısa arqumentlərinin məcburi qaydada verilməsini istəmiriksə, funksiyanın elanı zamanı onları default (susmaya görə) qiymətlərlə təyin etməliyik. Belə arqumentlər default arqumentlər adlanır. Funksiya çağrıldığı zaman bu arqumentlər verilməsə, susma halına görə onlar öz qiymətlərini saxlamış olacaqlar.
Aşağıdakı proqramda bir arqumenti default kimi təyin olunan funksiya və ondan necə istifadə edilməsi göstərilir:

>>> def fee(amount, currency = 'AZN'): 
        print(amount, currency)

>>> fee(50)
50 AZN
>>> fee(20, 'USD') 
20 USD
>>>

Gördüyünüz kimi, biz funksiyanı çağırarkən ikinci arqumenti (valyutanı) göstərməsək də, bu default (susmaya görə) qiymət kimi AZN qəbul ediləcək. Default arqument verildiyi təqdirdə, həmin qiymət (USD) funksiyaya ötürülmüş olacaq.
Burada bir vacib məqamı da qeyd etmək yerinə düşər. Belə ki, funksiyanı elan edərkən default arqumentlər məcburi arqumentlərdən sonra təyin olunmalıdır. Əks halda, interpretator xəta qeydə alacaq:

>>> def fee(currency = 'AZN', amount): 
        print(amount, currency)

SyntaxError: non-default argument follows default argument 
>>>

İxtiyari uzunluqlu arqumentlər

Funksiya elan edilərkən ona ötürüləcək arqumentlərin sayı öncədən məlum deyilsə, ixtiyari uzunluqlu arqumentlərdən istifadə oluna bilər. Funksiyaya bu zaman ixtiyari sayda açar sözlü olmayan arqumentlər ötürüləcəksə, funksiya parametrinin önünə tək ulduz (*) işarəsi qoyulmalıdır. Əgər funksiyaya ixtiyari sayda açar sözlü arqumentlər ötürüləcəksə, onda da funksiya parametrinin önünə qoşa ulduz (**) işarəsi qoyulmalıdır. Birinci halda ötürüləcək arqumentlər kortejdə, ikinci halda isə lüğətdə toplanmış olacaq. Bir funksiyaya eyni zamanda həm ixtiyari sayda açar sözlü olmayan, həm də ixtiyari sayda açar sözlü arqumentlər ötürülə bilər. Bu halda açar sözlü arqumentlər, açar sözlü olmayan arqumentlərdən sonra yazılmalıdır.
Aşağıdakı nümunələri nəzərdən keçirək:

>>> def fruits(*args): 
        print('Meyvələr\n')
        for i in args: 
            print(i)

>>> fruits('alma', 'armud', 'portağal') 
Meyvələr

alma 
armud 
portağal 
>>>
>>> def fruits(**kwargs): 
        print('Meyvələrdə vitaminlər\n')
        for i in kwargs: 
            print(i, kwargs[i], sep = ': ')

>>> fruits(alma = 'B, C', armud = 'B, C, E, K', 
           portağal = 'A, B, C, E')

Meyvələrdə vitaminlər

armud: B, C, E, K 
portağal: A, B, C, E 
alma: B, C
>>>

Sonda bir məsələni də nəzərinizə çatdıraq ki, funksiyalar bütün növ (mütləq, açar sözlü, default, ixtiyari uzunluqlu) arqumentləri eyni zamanda qəbul edə bilər.

Qeyri-lokal dəyişənlər

Yuxarıdakı misalda əsas proqram, funksiya və daxili funksiyada fərqli dəyişənlərdən istifadə etdik. Bəs, görəsən, eyniadlı dəyişənlərdən istifadə etsəydik, nə baş verərdi?

>>> def outer(): 
        def inner():
            x = 2
            print("inner:", x) 
        
        x = 1
        inner() 
        print("outer:", x)


>>> x = 0
>>> outer()
inner: 2
outer: 1
>>> print("global:", x) 
global: 0
>>>

Öncə də qeyd etdiyimiz kimi, üst səviyyədə elan olunan dəyişənlər aşağı səviyyədə yenidən təyin ediləndə onlar lokallaşdırılmış olur. Məhz bu səbəbdən proqramın x qlobal dəyişəninin qiyməti dəyişməz qaldı və eyni məntiqlə də outer() funksiyası daxilində təyin edilən x dəyişəni öz qiymətini saxlamış oldu.
Xatırlayırsınızsa, biz qlobal dəyişənin qiymətini funksiya daxilində dəyişə bilmək üçün global açar sözündən istifadə edirdik. Daxili funksiya içərisində də üst (xarici) funksiya dəyişəninin qiymətini nonlocal açar sözündən istifadə etməklə dəyişmək mümkündür:

>>> def outer(): 
        def inner():
            nonlocal x
            x = 2 
            print("inner:", x)
        
        x = 1
        inner() 
        print("outer:", x)


>>> x = 0
>>> outer()
inner: 2
outer: 2
>>> print("global:", x) 
global: 0
>>>

Beləliklə, qeyri-lokal (nonlocal) dəyişənlər lokal təsir sahəsində təyin olunmayan dəyişənlərdir. Eyni zamanda, misaldan da gördüyünüz kimi, onlar qlobal da deyildir. Bu cür dəyişənlərdən, əsasən, iç-içə və anonim funksiyalarda istifadə olunur.
Sonda onu da qeyd edək ki, daxili funksiya içərisindən də qlobal dəyişənin qiymətini dəyişmək mümkündür. Bunun üçün yenə də global açar sözündən istifadə edilməlidir:

>>> def outer(): 
        def inner():
            global x
            x = 2 
            print("inner:", x)

        x = 1
        inner() 
        print("outer:", x)


>>> x = 0
>>> outer()
inner: 2
outer: 1
>>> print("global:", x) 
global: 2
>>>

Baytlar massivi

Python proqramlaşdırma dilində baytlarla işləmək üçün nəzərdə tutulan ikinci tip isə bytearray (baytlar massivi) tipidir. Bundan öncə tanış olduğumuz bytes tipli obyektlərə tətbiq edilən metod və əməliyyatlar bytearray obyektləri üçün də keçərlidir. Bununla belə, bytes tipindən fərqli olaraq, bytearray tipinin obyektlərini bilavasitə dəyişmək mümkündür. Məhz bu məqsədlə onlar üçün əlavə metodlar nəzərdə tutulmuşdur.
İndi isə gəlin bytearray obyektlərini meydana gətirən üsulları nəzərdən keçirək.

bytearray([sətir, kodlaşdırma[, xətalar]])

Bu funksiyadan parametrlərsiz istifadə edildiyi təqdirdə boş bytearray obyektini qaytarır:

>>> bytearray() 
bytearray(b'') 
>>>

Verilmiş sətri bytearray obyektinə çevirmək üçün funksiyadan minimum iki parametrlə istifadə olunmalıdır. Sadəcə sətir verilib, kodlaşdırma göstərilmədiyi təqdirdə xəta qeydə alınacaq:

>>> bytearray('Python', 'utf-8') 
bytearray(b'Python')
>>> bytearray('Python')
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module> 
    bytearray('Python')
TypeError: string argument without an encoding 
>>>

Funksiyanın üçüncü parametri olan xətalar isə xəta emaledicisinin göstərilməsi üçündür. Siz onlarla əvvəlki mövzuda tanış olmuşdunuz.
Aşağıdakı nümunələri nəzərdən keçirin:

>>> bytearray('Azərbaycan', 'ascii', 'strict') 
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    bytearray('Azərbaycan', 'ascii', 'strict')
UnicodeEncodeError: 'ascii' codec can't encode character 
'\u0259' in position 2: ordinal not in range(128)
>>> bytearray('Azərbaycan', 'ascii', 'replace') 
bytearray(b'Az?rbaycan')
>>> bytearray('Azərbaycan', 'ascii', 'ignore') 
bytearray(b'Azrbaycan')
>>> bytearray('Azərbaycan', 'ascii', 'xmlcharrefreplace') bytearray(b'Az&#601;rbaycan')
>>> bytearray('Azərbaycan', 'ascii', 'backslashreplace') bytearray(b'Az\\u0259rbaycan')
>>> bytearray('Azərbaycan', 'ascii', 'namereplace') 
bytearray(b'Az\\N{LATIN SMALL LETTER SCHWA}rbaycan') 
>>>

bytearray([ardıcıllıq])

Bu funksiya 0 ilə 255 (hər ikisi daxil olmaqla) aralığında yerləşən tam ədədlərin ardıcıllığını bytearray obyektinə çevirməyə imkan verir. Verilmiş ədəd aralığa daxil deyilsə, ValueError xətası qeydə alınır:

>>> bytearray([97, 108, 109, 97]) 
bytearray(b'alma')
>>> bytearray([601, 116, 105, 114]) 
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module> 
   bytearray([601, 116, 105, 114])
ValueError: byte must be in range(0, 256) 
>>>

Diqqətlə baxsanız, görəcəksiniz ki, ardıcıllıq şəklində verdiyimiz tam ədədlər Unicode simvollarının kodlarıdır.

bytearray(ədəd)

Burada ədəd elementlərin sayıdır. Hər bir element sıfırıncı simvolu özündə saxlayır. Funksiya miqdarı verilmiş bu elementləri baytlar massivinə çevirir:

>>> bytearray(5) 
bytearray(b'\x00\x00\x00\x00\x00') 
>>>

bytearray.fromhex(sətir)

Burada sətir verilmiş simvolların onaltılıq say sistemindəki kodlarından ibarətdir. Funksiya bu sətri bytearray tipli obyektə çevirir. Çevrilmə zamanı sətirdəki boşluqlar nəzərə alınmır:

>>> bytearray.fromhex("61 6c 6d 61") 
bytearray(b'alma')
>>>

Dəyişən tip olduğuna görə baytlar massivini dəyişmək olur:

>>> s = bytearray('Python', 'utf-8') 
>>> s
bytearray(b'Python') 
>>> s[0] = 74
>>> s 
bytearray(b'Jython') 
>>>

bytearray obyektlərini dəyişmək üçün aşağıdakı metodlardan da istifadə edilə bilər:

bytearray.append(ədəd)

Bu metod obyektin sonuna kodu ədəd şəklində göstərilmiş elementi əlavə edir:

>>> s = bytearray('alma', 'utf-8') 
>>> s
bytearray(b'alma')
>>> s.append(110)
>>> s 
bytearray(b'alman') 
>>>

bytearray.extend([ardıcıllıq])

Bu metod obyektin sonuna kodları ardıcıllıq şəklində verilmiş elementləri əlavə edir:

>>> s = bytearray('alman', 'utf-8') 
>>> s
bytearray(b'alman')
>>> s.extend([108, 97, 114]) 
>>> s
bytearray(b'almanlar') 
>>>

Burada ardıcıllıq baytlar ardıcıllığı kimi də verilə bilər:

>>> s = bytearray('alman', 'utf-8') 
>>> s
bytearray(b'alman')
>>> s.extend(b'lar')
>>> s 
bytearray(b'almanlar') 
>>>

Baytlar massivinin sonuna bir neçə elementi + və += operatorları vasitəsilə də əlavə etmək olar:

>>> s = bytearray('kar', 'utf-8') 
>>> s
bytearray(b'kar')
>>> s = s + b'van'
>>> s 
bytearray(b'karvan')
>>> s += b'saray'
>>> s 
bytearray(b'karvansaray') 
>>>

bytearray obyektinin sonuna bir neçə elementi obyekt diliminə qiymət mənimsətməklə də əlavə etmək mümkündür:

>>> s = bytearray('bala', 'utf-8') 
>>> s[len(s):] = b'ban'
>>> s
bytearray(b'balaban')
>>>

bytearray.insert(indeks, ədəd)

Bu metod bytearray obyektinə kodu ədəd şəklində verilmiş elementi indeks kimi göstərilmiş mövqedən daxil edir:

>>> s = bytearray('zaan', 'utf-8') 
>>> s.insert(2, 109)
>>> s
bytearray(b'zaman')
>>>

bytearray.pop(indeks)

Bu metod bytearray obyektinin indeks kimi göstərilmiş mövqedəki elementini silir və onun kodunu qaytarır. Əgər indeks boş buraxılıbsa, ən son element silinir və kodu qaytarılır:

>>> s = bytearray('bazzar', 'utf-8')
>>> s.pop(2) 
122
>>> s
bytearray(b'bazar')
>>> s.pop() 
114
>>> s 
bytearray(b'baza') 
>>>

bytearray.remove(ədəd)

Bu metod bytearray obyekti daxilində kodu ədəd şəklində göstərilmiş ilk elementi taparaq silir. Göstərilmiş element obyekt daxilində yoxdursa, ValueError xətası qeydə alınır:

>>> s = bytearray('salat', 'utf-8') 
>>> s.remove(108)
>>> s
bytearray(b'saat')
>>> s.remove(97) 
>>> s 
bytearray(b'sat') 
>>> s.remove(108)
Traceback (most recent call last):
  File "<pyshell#25>", line 1, in <module>
    s.remove(108)
ValueError: value not found in bytearray 
>>>

bytearray obyektindən element(lər)i silmək üçün del operatorundan da istifadə edilə bilər:

>>> s = bytearray('dallan', 'utf-8') 
>>> del s[2]
>>> s
bytearray(b'dalan')
>>> del s[2:4] 
>>> s 
bytearray(b'dan') 
>>>

bytearray.reverse()

Bu metod bytearray obyektinin elementlərini tərs ardıcıllıqda düzür:

>>> s = bytearray('zaman', 'utf-8') 
>>> s.reverse()
>>> s
bytearray(b'namaz')
>>>

bytearray.decode(kodlaşdırma, xətalar)

Verilmiş bytearray obyektini str (sətir) obyektinə çevirmək üçün decode() metodundan istifadə edilir. Burada kodlaşdırma və xətalar parametrlərinin yazılması məcburi deyil. Parametrlər boş buraxıldığı təqdirdə default olaraq (susmaya görə) kodlaşdırma utf-8, xəta emaledicisi də strict qəbul ediləcək. Digər xəta emaledicilərinin istifadəsi əvvəlki mövzularda izah edildiyi kimidir. Müxtəlif kodlaşdırmalar ilə bağlı Python dilinin rəsmi dokumentasiyasında (https://docs.python.org/3.14) Standart Kodlaşdırmalar Cədvəlinə baxa bilərsiniz.
Aşağıdakı nümunələri nəzərdən keçirin:

>>> s1 = bytearray('Gürzə', 'utf-8') 
>>> s2 = bytearray('Python', 'utf-8') 
>>> s1.decode()
'Gürzə'
>>> s2.decode("ascii", "strict") 
'Python'
>>>

Baytlar massivini sətrə çevirmək üçün str() funksiyasından da istifadə edilə bilər:

>>> s = bytearray('Azərbaycan', 'utf-8') 
>>> s 
bytearray(b'Az\xc9\x99rbaycan')
>>> str(s, 'utf-8')
'Azərbaycan' 
>>>