Среда је, што значи да је време за нови чланак, а како смо већ загазили у Python свет, наставићемо да крчимо свој пут кроз њега. У данашњој лекцији ћу писати о if наредби, која нам је предуслов за наставак приче о колекцијама, пошто вам планирам показати неколико начина како манипулацију листи или парова можете подигнути на нови ниво.

Ако нисте прочитали претходну лекцију, то можете учинити на овом линку.

if наредба

if наредба представља најчешћи начин управљања током извршавања програма. Она на основу прослеђене вредности, која је имплицитно или експлицитно bool вредност, одлучује које ће идуће команде бити извршене. Када кажем имплицитно или експлицитно, мислим да ако није прослеђена вредност која је bool типа, Python ће је аутоматски конвертовати. Нпр. празан стринг или листа се конвертују у False, док би стринг ‘hello’ био конвертован у True.

bool тип може имати две вредности: тачно (True) или нетачно (False). Оператори коју су доступни су:

or: враћа True ако је било која од датих вредности тачна

and: враћа True ако су све дате вредности тачне

not: враћа True ако је прослеђена негативна вредност

==: враћа True ако су две прослеђене вредности једнаке

!=: враћа True ако су две прослеђене вредности различите

is: враћа True ако су у питању два иста објекта

На идућем примеру можемо видети управљање током извршавања програма у зависности од услова:

a = 5

if a > 3:
    print('a је веће од 3!')

Испис:

a је веће од 3!

НАПОМЕНА: Обратите пажњу на увлачење, које у Python синтакси мења употребу блокова (витичастих заграда). Све што је увучено сматра се да припада тренутној наредби, функцији, класи или сл.

Пошто је у питању једноставна if наредба, која има само један израз, можемо је заменити једнолинијским записом.

a = 5

if a > 3: print('a је веће од 3!')

Испис:

a је веће од 3!

Како би наш програм постао сложенији можемо додати и подразумевани случај (else), који ће се извршити ако се не задовољи услов у if наредби.

a = 5

if type(a) == int:  # функција type враћа тип прослеђеног објекта
    print('a је цео број!')
else:
    print('a није цео број!')

b = 'Поздрав из Новог Сада!'

if type(b) == int:
    print('b је цео број!')
else:
    print('b није цео број!')

Испис:

a је цео број!
b није цео број!

Осим могућности додавања подразумеваног случаја, могуће је везати више if наредби са elif синтаксом (скраћено од else if). Када вежемо овакве случајеве, уместо писања if наредбе за сваки услов, штедимо ресурсе јер ће се извршавање заустави онога тренутка када случај буде испуњен. Пример:

a = 'Поздрав из Новог Сада!'

if type(a) == int:
    print('a је цео број!')
elif type(a) == str:
    print('a је стринг!')
elif type(a) == float:
    print('a је децимални број!')
else:
    print('Не могу да одредим тип!')

Испис:

a је стринг!

Погледајмо начин извршавања овог записа и записа када користимо само if, а не elif, случајеве, где то утиче и на логику извршавања.

a = 'Поздрав из Новог Сада!'

print(print('Ја враћам None вредност'))
# Све функције у Python-у подразумевано враћају None вредност, print није изузетак.
# Side effect print функције ће бити испис на екрану, али њена повратна вредност је None.
# То ћемо видети јер ће се прво извршити унутрашња функција која ће исписати прослеђени стринг и вратити None.
# А затим ће спољашња функција исписати ту повратну вредност унутрашње функције, односно None.

print('-' * 10)

# Пошто None није bool вредност она се имплицитно конвертује у њу, односно None ће постати False.
# Како је нама потребна True вредност због овог експеримента ми ћемо је негирати са not.
# not True претвара у False, а False у True
if not print('Извршено 1. поређење') and type(a) == int:
    print('a је цео број!')
elif not print('Извршено 2. поређење') and type(a) == str:
    print('a је стринг!')
elif not print('Извршено 3. поређење') and type(a) == float:
    print('a је децимални број!')
else:
    print('Извршен else')  # Овде није потребно негирати јер се налази у блоку, а не у услову.
    print('Не могу да одредим тип!')

print('-' * 10)

# Сада исти пример са само if наредбама, без elif-ова.
if not print('Извршено 1. поређење') and type(a) == int:
    print('a је цео број!')
if not print('Извршено 2. поређење') and type(a) == str:
    print('a је стринг!')
if not print('Извршено 3. поређење') and type(a) == float:
    print('a је децимални број!')
else:  # Приметите да се else односи само на последње наведен if, а не на све if-ове пре њега.
    print('Извршен else')
    print('Не могу да одредим тип!')

Испис:

Ја враћам None вредност
None
----------
Извршено 1. поређење
Извршено 2. поређење
a је стринг!
----------
Извршено 1. поређење
Извршено 2. поређење
a је стринг!
Извршено 3. поређење
Извршен else
Не могу да одредим тип!

Ако вам је нејасно, слободно питајте за појашњење у коментарима.

if/else комбинацију је, такође, могуће скраћено записати и то на следећи начин:

a = 5
print('a је веће од 3!') if a > 3 else print('a је мање или једнако 3!')

# Могуће је и везати неколико if/else комбинације, при чему се оне записане на овај начин понашају као if/elif/else запис
print('a је веће од 5') if a > 5 else print('a је једнако 5!') if a == 5 else print('a је мање од 5!')

Испис:

a је веће од 3!
a је једнако 5!

Примери осталих оператора:

a = 3
b = 4

if a == 3 and b == 4:
    print('Оба услова су испуњена!')

if a == 3 or b == 3:
    print('Било који од датих услова је испуњен!')

if not False:
    print('Негирани услов је вратио True!')

Испис:

Оба услова су испуњена!
Било који од датих услова је испуњен!
Негирани услов је вратио True!

Када проверавамо да ли је нека вредност None вредност, није препоручљиво користити оператор ==, него оператор is. Оператор == је могуће редефинисати (о чему ћу у некој од наредних лекција), док оператор is увек проверава да ли је у питању исти објекат. Пример:

a = {'key': 'value'}
b = {'key': 'value'}

print('Сложени типови')
print(f'a is b: {a is b}')  # Иако је вредност иста, у питању су два објекта. is управо то проверава.
print(f'a == b: {a == b}')  # == проверава само вредност

print('-' * 10)

a = 3
b = 3

print('Прости типови')
print(f'a is b: {a is b}')  # Код простих објеката због оптимизације, реч је о истим објектима. Погледајте прошлу лекцију о меморији.
print(f'a == b: {a == b}')

print('-' * 10)

a = None

print('a = None')
print(f'a == None: {a == None}')  # Оператор == је могуће редефинисати, тако да се не можемо увек поуздати у његову тачност када поредимо са None.
print(f'a is None: {a is None}')

print('-' * 10)

print('Редефинисан == оператор')
# Пример када се не можемо поуздати у резултат == оператора. Више о овоме ће бити у једној од наредних лекција.
class CustomClass:  # Дефинишемо класу CustomClass
    def __init__(self, param):  # __init__ метода представља конструктор класе
        self.param = param  # У њој можемо везати атрибуте за инстанцу (објекат) класе

    def __eq__(self, other):  # eq је скраћено equivalent, што значи да метода __eq__ редефинише оператор једнакости: ==
        return True  # У нашем случају поређење ће увек враћати True


# Позивом класе као функције ми позивамо конструктор (__init__) методу класе
# Повратна вредност конструктора је инстанца (објекат) те класе, дефинисано у надкласи Object коју све класе имплицитно наслеђују
custom_object = CustomClass(param='Мој параметар.')
print(f'Да проверимо да наш објекат није None вредност, можемо преко позива атрибута custom_object.param: {custom_object.param}')
print(f'custom_object == None: {custom_object == None}')  # Позиова се метода __eq__
print(f'custom_object is None: {custom_object is None}')  # Гледа се референца ка меморији

Испис:

Сложени типови
a is b: False
a == b: True
----------
Прости типови
a is b: True
a == b: True
----------
a = None
a == None: True
a is None: True
----------
Редефинисан == оператор
Да проверимо да наш објекат није None вредност, можемо преко позива атрибута custom_object.param: Мој параметар.
custom_object == None: True
custom_object is None: False

Овиме завршавам данашњи чланак. Видимо се у суботу, stay Pythonic!