Formatlaşdırmanın yeni üsulu

Mövzumuzun əvvəlində qeyd etmişdik ki, Python proqramlaşdırma dilində çıxışların formatlaşdırılmasında üstünlük verilən üsul string sinfinin format metodudur. Çox çevik olan format metodunun ümumi yazılış forması aşağıdakı kimidir:

şablon.format(p0, p1, ..., k0=v0, k1=v1, ...)

Burada şablon formatlaşdırmaq istədiyimiz sətirdir. Bu sətrə bir və ya bir neçə format kodu, başqa sözlə, əvəzlənən sahələr daxil edilir. Fiqurlu {} mötərizə daxilində yazılan format kodları verilmiş arqumentləri formatlaşdıraraq sətir daxilində öz yerinə qoyur. Buradakı arqumentlər isə iki növdə verilə bilər: mövqeli (p0, p1,…) və açar sözlü (k0=v0, k1=v1,…). Qeyd edək ki, formatlaşdırma zamanı mövqeli və açar sözlü arqumentləri həm ayrı-ayrılıqda, həm də eyni zamanda (öndə mövqelilər, ardınca açar sözlülər olmaqla) istifadə etmək mümkündür.

Aşağıdakı sxem format metodunun mövqeli arqumentlərlə necə işlədiyini göstərir:


Yuxarıdakı yazılışdan da gördüyünüz kimi, mövqeli arqumentlər format kodları vasitəsilə şablonda (formatlaşdırılan sətirdə) öz yerlərinə qoyulur. Bizim nümunədə iki format kodu var: {0:5d}{1:8.2f}. Hər bir format kodu sıra sayı, qoşa nöqtə və format şəklindən (opsiya, genişlik və tip) ibarətdir.

>>> "Məhsul kod:{0:5d}, qiymət:{1:8.2f}".format(254, 65.076)
'Məhsul kod:  254, qiymət:   65.08'
>>>

Aşağıda verilmiş digər nümunələri də nəzərdən keçirin:

>>> "1-ci arqument: {0}, 2-ci arqument: {1}".format(55,11)
'1-ci arqument: 55, 2-ci arqument: 11'
>>> "2-ci arqument: {1}, 1-ci arqument: {0}".format(55,11)
'2-ci arqument: 11, 1-ci arqument: 55'
>>> "2-ci arqument: {1:3d}, 1-ci arqument: {0:7.2f}".format(55.23,11)
'2-ci arqument:  11, 1-ci arqument:   55.23'
>>> "1-ci arqument: {}, 2-ci arqument: {}".format(55,11)
'1-ci arqument: 55, 2-ci arqument: 11'
>>> "Müxtəlif dəqiqlik: {0:6.2f} və {0:6.3f}".format(1.6238)
'Müxtəlif dəqiqlik:   1.62 və  1.624'
>>>

Burada bir məqamı da qeyd edək ki, mövqeli arqumentlərdən verilmiş ardıcıllıqda istifadə edildiyi təqdirdə şablondakı format kodlarında sıra sayını, dördüncü nümünədə olduğu kimi, boş buraxmaq olar.
Aşağıdakı sxem isə format metodunun açar sözlü arqumentlərlə necə işlədiyini göstərir:

Sxemdən gördüyünüz kimi, açar sözlü arqumentlər də mövqeli arqumentlər kimi format kodları vasitəsilə şablonda (formatlaşdırılan sətirdə) öz yerlərinə qoyulur. Burada fərq yalnız ondan ibarətdir ki, arqumentlər açar=qiymət şəklində göstərilir.

>>> "Məhsul kod: {a:5d}, qiymət: {b:8.2f}".format(a=254, b=65.076)
'Məhsul kod:   254, qiymət:    65.08'
>>>

Çıxışları format metodu ilə formatlaşdırarkən format kodlarında əlavə olaraq aşağıdakı opsiyalardan da istifadə edə bilərsiniz:

OpsiyaTəyinatı
<Çıxış veriləni soldan nizamlanır. Sətirlər üçün bu, adətən, default (susmaya görə) nizamlanmadır.
>Çıxış veriləni sağdan nizamlanır. Ədədlər üçün bu default (susmaya görə) nizamlanmadır.
^Çıxış veriləni onun üçün ayrılmış yerdə mərkəzdən nizamlanır.
0Format şəkli daxilində genişlikdən öncə yazıldıqda, ədəd tipli çıxışların önünü boş mövqelərin sayı qədər sıfırlarla tamamlayır.
,Ədəd tipli çıxışları minlik ayırıcı simvol ilə çıxarır.
=Ədəd tipli çıxışlarda ədəd ilə işarəsinin (əgər varsa) arasını ön məsafə (və ya verilmiş simvol) ilə doldurur.
+Ədəd tipli çıxış verilənlərinin önündə mənfi ədədlərdə olduğu kimi, müsbət ədədlərdə də onların işarəsini çıxarır. 
Çıxış veriləni yalnız mənfi ədəd olduqda önündə onun işarəsini çıxarır. Bu, onsuz da default olaraq (susmaya görə) belədir.
boşluqÇıxış veriləni müsbət ədəd olduqda önünə boşluq (probel) qoyur.

Aşağıda verilmiş nümunələri nəzərdən keçirin:

>>> '{0:<20s} {1:4d}'.format('Təvəllüd:',1978)
'Təvəllüd:            1978'
>>> '{0:>20s} {1:4d}'.format('Təvəllüd:',1978)
'           Təvəllüd: 1978'
>>> '{0:^20s} {1:4d}'.format('Təvəllüd:',1978)
'     Təvəllüd:       1978'
>>>
>>> 'Sıra sayı: {:06d}'.format(125)
'Sıra sayı: 000125'
>>> 'Büdcə kəsiri: {:,d} manat'.format(1698000000)
'Büdcə kəsiri: 1,698,000,000 manat'
>>> '{:=6d}'.format((-23))
'-   23'
>>> "Anarın {:*=6d} manat pulu var".format(15)
'Anarın ****15 manat pulu var'
>>>
>>> 'Bakı {:+2d}°C'.format(5)
'Bakı +5°C'
>>> 'Bişkek {:+2d}°C'.format(-5)
'Bişkek -5°C'
>>> 'Aşqabad {:-2d}°C'.format(12)
'Aşqabad 12°C'
>>> 'Astana {:-2d}°C'.format(-12)
'Astana -12°C'
>>>
>>> '{: d}'.format(15)
' 15'
>>> '{: d}'.format(-15)
'-15'
>>>

Yeri gəlmişkən, bir məsələni də aydınlaşdıraq. Diqqət yetirsəniz, görəcəksiniz ki, formatlaşdırılmış çıxışlar ekrana dırnaq işarələri arasında çıxır:

>>> "{cnt} - {cap}".format(cnt = "Azərbaycan", cap = "Bakı")
'Azərbaycan - Bakı'
>>>

print() funksiyasından istifadə etməklə “dırnaqsız” çıxış ala bilərik:

>>> print("{cnt} - {cap}".format(cnt = "Azərbaycan", cap = "Bakı"))
Azərbaycan - Bakı
>>>

Burada əlavə dəyişəndən istifadə etməklə yazılışı sadələşdirmək də mümkündür:

>>> s = "{cnt} - {cap}"
>>> print(s.format(cnt = "Azərbaycan", cap = "Bakı"))
Azərbaycan - Bakı
>>>

format metodunda lüğətlərin istifadəsi

Artıq bilirsiniz ki, yeni üsulla çıxışlar mövqeli və/və ya açar sözlü arqumentlərdən istifadə etməklə formatlaşdırılır. Mövqeli arqumetlərlə bağlı qeyri-adi heç nə yoxdur, amma açar sözlü arqumentlərə diqqətlə baxsanız, sizə əvvəlki mövzulardan tanış gələn bir şey görəcəksiniz:

>>> s = "{cnt} - {cap}"
>>> print(s.format(cnt = "Azərbaycan", cap = "Bakı"))
Azərbaycan - Bakı
>>>

Yəqin ki, xatırladınız, buradakı arqumentlər lüğətdir, yəni dictionary tipindəki verilənlərdir. O zaman yuxarıdakı misalı aşağıdakı şəkildə də yaza bilərik:

>>> cnt_cap = {"cnt":"Azərbaycan", "cap":"Bakı"}
>>> s="{cnt} - {cap}"
>>> print(s.format(**cnt_cap))
Azərbaycan - Bakı
>>> 

Burada arqumentlərin sayı lüğətin elementlərinin sayından asılıdır. Başqa sözlə, format metoduna ötürülən açar sözlü arqumentlərin sayı ixtiyaridir.  Məhz buna görə də, metod daxilindəki cnt_cap parametrinin önünə qoşa ulduz (**) simvolu qoyulmalıdır. Xatırlayırsınızsa, biz funksiyaları ixtiyari uzunluqlu arqumentlərlə təyin edərkən də bu qoşa ulduzdan (**) istifadə edirdik.

Gəlin daha bir proqram yazaq. Bu proqram Türk dövlətlərinin adlarını paytaxtları ilə bərabər ekrana çıxaracaq:

turk_rep = {"Azərbaycan":"Bakı",
            "Türkiyə":"Ankara",
            "Qazaxıstan":"Astana",
            "Qırğızıstan":"Bişkek",
            "Özbəkistan":"Daşkənd",
            "Türkmənistan":"Aşqabad",
            "Macarıstan":"Budapeşt"
            "ŞKTR":"Şimali Lefkoşa"}

print("Türk Dövlətləri və paytaxtları:")
for a in turk_rep:
    s = a + " - {" + a + "}"
    print(s.format(**turk_rep))

Proqramı skriptdə yazın və icra edin.

format metodunda lokal dəyişən adlarının istifadəsi

Python proqramlaşdırma dilində locals() adlı daxili bir funksiya var. Bu funksiya cari təsir sahəsinin lokal dəyişənləri və onların qiymətlərindən ibarət lüğəti qaytarır. Lokal dəyişənlərin adları lüğətin açarları, bu dəyişənlərin müvafiq qiymətləri isə açarların qiymətləri olur.
Aşağıdakı nümunəni nəzərdən keçirək:

>>> a = 11
>>> b = 22
>>> def f(): return 33

>>> locals()
{'b': 22, '__name__': '__main__', '__spec__': None, 'a': 11, 'f': <function f at 0x105654620>, '__package__': None, '__doc__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__builtins__': <module 'builtins' (built-in)>}
>>>

Biz locals() funksiyasının qaytardığı lüğətdən format metodunun parametri kimi istifadə edə bilərik:

>>> print("a={a}, b={b}, f={f}".format(**locals()))
a=11, b=22, f=<function f at 0x105654620>
>>>

Çıxışların formatlaşdırılması məqsədilə string sinfində digər sətir metodları da nəzərdə tutulmuşdur. Həmin metodlarla müvafiq bölmədə tanış ola bilərsiniz.

Formatlaşdırmanın köhnə üsulu

Bildiyiniz kimi, Guido van Rossum Python dilini meydana gətirərkən C dilindən də müəyyən sintaksis konstruksiyaları götürmüşdür. C dilində isə sırf formatlı çıxışlar üçün nəzərdə tutulan xüsusi printf()sprintf() kimi funksiyalar vardır. Python dilinə həmin funksiyalar keçməsə də, onların funksionallığını təmin edən % (modul) operatorundan adi print() funksiyası daxilində istifadə etmək mümkündür. Modul (riyazi modul ilə qarışdırmayın) operatoruna çox vaxt sətir modulu və ya sətir interpolyasiyası da deyilir.
Aşağıdakı sxem sətir modulu operatorunun necə işlədiyini göstərir:

Yuxarıdakı yazılışdan da gördüyünüz kimi, print() funksiyasına bütöv olaraq ötürülən parametr əslində üç hissədən ibarətdir:

Burada qiymətlər kortejinin elementləri literal, dəyişən və ya ixtiyari riyazi ifadədən ibarət ola bilər. Kortejin elementləri placeholders (yerləşdirmə göstəriciləri) vasitəsilə sətir formatında öz yerlərinə qoyulur. Bizim nümunədə iki (%5d%8.2f) placeholder var.
Placeholderin yazılışının ümumi sintaksisi aşağıdakı kimidir:

%[bayraqlar][genişlik][.dəqiqlik]tip

Burada bayraqlar bəzi konversiya (çevrilmə) tiplərinin nəticəsinə təsir edən parametrlərdir. Bu konversiya parametrlərinin istifadəsi opsionaldır (istəyə bağlıdır). Aşağıdakı cədvəldə onlarla tanış ola bilərsiniz:

BayraqTəyinatı
#o, x və ya X spesifikatorları ilə istifadə edildiyi zaman çıxış qiymətlərinin önünə müvafiq olaraq 0, 0o, 0O, 0x və ya 0X simvolları əlavə edilir.
0Ədədi qiymətlər üçün konversiya nəticəsi ön məsafəsiz çıxır.
Konversiya nəticələri soldan nizamlanır.
+Ədədi qiymətlərdə istifadə edildiyi zaman onların işarəsi (“+” və ya “-“) konversiya nəticəsinin önündə göstərilir.
boşluqBayraq olaraq boşluq (probel) yazıldıqda müsbət çıxış qiymətlərinin önünə boşluq (probel) qoyulur.

Placeholderin yazılışında göstərilən genişlik ədədi qiymətlərdə çıxış veriləni üçün soldan sağa ayrılmış xanaların ümumi sayıdır. Əgər çıxış veriləni həqiqi ədəddirsə, vergüldən sonrakı rəqəmlərinin sayını bildirmək üçün dəqiqlik də göstərilməlidir:

Əgər çıxış qiymətində vergüldən sonrakı rəqəmlərin sayı onun üçün qeyd olunan dəqiqlikdən çoxdursa, yuvarlaqlaşdırma, azdırsa, sıfırlarla tamamlama baş verəcək.
Aşağıdakı cədvəldə isə placeholderdə göstərilə bilən tiplər verilmişdir:

KonversiyaTəyinatı
dÇıxışa işarəli onluq tam ədəd çıxarır.
iÇıxışa işarəli onluq tam ədəd çıxarır.
uÇıxışa işarəsiz onluq tam ədəd çıxarır.
oÇıxışa işarəsiz səkkizlik ədəd çıxarır.
xÇıxışa işarəsiz onaltılıq ədəd çıxarır (aşağı registr).
XÇıxışa işarəsiz onaltılıq ədəd çıxarır (yuxarı registr).
eÇıxışa eksponensial formatda həqiqi ədəd çıxarır (aşağı registr).
EÇıxışa eksponensial formatda həqiqi ədəd çıxarır (yuxarı registr).
fÇıxışa onluq həqiqi ədəd çıxarır.
FÇıxışa onluq həqiqi ədəd çıxarır.
gEksponent -4-dən böyük və ya dəqiqlikdən kiçik olduqda e,əks halda, f konversiyası ilə eynidir.
GEksponent -4-dən böyük və ya dəqiqlikdən kiçik olduqda E,əks halda, F konversiyası ilə eynidir.
cÇıxışa tək simvol çıxarır.
rÇıxışa sətir çıxarır. (istənilən Python obyektini repr() funksiyası ilə çevirir).
sÇıxışa sətir çıxarır (istənilən Python obyektini str() funksiyası ilə çevirir).
aÇıxışa sətir çıxarır (istənilən Python obyektini ascii() funksiyası ilə çevirir).
%Çıxışa yalnız % simvolunu çıxarır.

İndi isə gəlin bizim misaldakı placeholderləri nəzərdən keçirək:

>>> print("Məhsul kod:%5d, qiymət:%8.2f" % (254, 65.076))
Məhsul kod:  254, qiymət:   65.08
>>>

Burada birinci olan %5d placeholderi kortejin ilk elementi olan 254 qiymətini sətir formatında öz yerinə yerləşdirir. Bu zaman çıxış veriləni üçün beş xanalıq yer ayrılır və o işarəli onluq tam ədəd şəklində konversiya olunur. Diqqət edin ki, çıxış veriləni üçün beş yer ayrıldığı halda onun özü üç rəqəmlidir. Məhz buna görə də, bu qiymət çıxışa önündə iki boşluqla gəlir.
Misalda ikinci olan %8.2f placeholderinə gəlincə isə görmək olar ki, o 65.076 qiymətini onluq həqiqi ədəd şəklində konversiya edir. Çıxış veriləni üçün ümumilikdə səkkiz, vergüldən sonrakı rəqəmlər üçün (dəqiqlik) iki xanalıq yer ayrılır. Dəqiqlik üçün ayrılan xanaların sayı bir vahid az olduğuna görə çıxışda ədəd bir mövqe yuvarlaqlaşdırılır.
Aşağıda verilmiş digər nümunələri də nəzərdən keçirin:

>>> print("%10.3e"% (425.07875))
     4.251e+02
>>> print("%10o"% (17))
            21
>>> print("%5.4X"% (54))
     0036
>>> print("%c"% ('A'))
A
>>> print("%s"% ('alma'))
alma
>>> print("Yalnız faiz simvolu: %%" % ())
Yalnız faiz simvolu: %
>>>
>>> print("%#5X"% (78))
     0X4E
>>> print("%#5o"% (33))
     0o41
>>> print("%+d"% (47))
+47
>>> print("%0d"% (42))
42
>>> print("%-5d"% (86))
86   
>>> print("% d"% (27))
     27
>>>

İlk baxışdan elə görünsə də, əslində formatlaşdırma print() funksiyasının bir parçası deyildir. Yazdığımız misallara diqqətlə nəzər yetirsəniz, görəcəksiniz ki, bütün hallarda print() funksiyasına ötürülən parametr sətir modulu (%) operatoru ilə formatlaşdırılan sətirdir. Köhnə üsulla çıxışları formatlaşdırarkən biz aşağıdakı ardıcıllıqdan da istifadə edə bilərdik:

>>> s = "Məhsul kod:%5d, qiymət:%8.2f" % (254, 65.076)
>>> print(s)
Məhsul kod:  254, qiymət:   65.08
>>>

Çıxışların formatlaşdırılması

Çıxışların formatlaşdırılması, başqa sözlə, çıxış verilənlərinin istifadəçilərə formatlı şəkildə təqdim edilməsi proqramlaşdırmada ən vacib məsələlərdən biridir. Biz bu dərsimizdə Python dilində çıxışların formatlaşdırılmasının müxtəlif üsullarından bəhs edəcəyik. Bununla belə sizə məsləhət görəcəyimiz üsul string sinfinin format metodudur. Bu üsul həm olduqca çevikdir, həm də Python dilinin fəlsəfəsinə uyğun gəlir. Gəlin tələsməyək və bütün üsulları bir-bir nəzərdən keçirək.

Biz indiyə qədər çıxış verilənlərini ekrana primitiv üsullarla çıxarırdıq. Ekrana çıxarılan məlumatlar birdən çox olduqda onları bir-birindən ayırmaq lazımdır. Bunun da ən sadə yolu ya print() funksiyasının sep parametrindən (ayırıcı) istifadə, ya da sətirləri konkatenasiya (birləşdirilmə) etməkdən ibarətdir.

Adi qaydada print() funksiyasında sep parametri yazılmır və interpretator onun qiymətini default olaraq boşluq qəbul edir. Bu zaman funksiyanın bir-birindən vergüllə ayrılan arqumentləri ekrana çıxarılanda aralarında boşluq olur:

>>> a = 78
>>> b = 0.19
>>> print(a, b, a * b) 
78 0.19 14.82
>>>

Zərurət olduqda biz sep parametrindən yararlanaraq onu ixtiyari qiymətlərlə təyin edə bilərik:

>>> a = 78
>>> b = 0.19
>>> print(a, b, a * b, sep = ',') 
78,0.19,14.82
>>> print(a, b, a * b, sep = '---') 
78---0.19---14.82
>>>

Aşağıdakı proqramda isə çıxışları formatlaşdırmaq üçün sətirlərin konkatenasiyasından istifadə olunur:

>>> a = 78
>>> b = 0.19
>>> print(str(a)+ " " +str(b)+" " +str(a * b)) 
78 0.19 14.82
>>>

Yuxarıda sadalanan bu üsullar nə qədər sadə olsa da, peşəkarlıq baxımından qənaətbəxş deyil.