W Pythonie wyrażenie if można zapisać w postaci jednolinijkowca:
1 |
expr1 if cond else expr2 |
Jednak łatwo wpaść w pułapkę. Takie wyrażenie zadziała:
1 |
<span class="kwd">print</span><span class="pun">(</span><span class="pln">price</span><span class="pun">-</span><span class="pln">bonus</span><span class="pun">)</span> <span class="kwd">if</span><span class="pln"> bonus_granted </span><span class="kwd">else</span> <span class="kwd">print</span><span class="pun">(</span><span class="pln">price</span><span class="pun">)</span> |
ale już takie nie:
1 2 |
print(price-bonus) if bonus_granted else price = 200 print(price-bonus) if bonus_granted else pass |
Ale po kolei:
price = 10
bonus = 1
bonus_granted = True
A teraz odpowiadając na pytanie. Przypomnijmy, że Pythonie można mieć statement i expressions:
- statement – coś robi i niekoniecznie cokolwiek zwraca. Przykładem statement jest pass i przypisanie wartości do zmiennych
- expression – to jest jedna lub więcej instrukcji, które coś zwracają. Przykładem expression jest np dowolny napis, dowolne obliczenie, ale też np. polecenie print (!!!!!!)
Jak sprawdzić czy coś jest expression? Prosto. Do zmiennej przypisz wynik wykonania polecenia, np.:
1 2 |
<span class="pln">x </span><span class="pun">=</span> <span class="kwd">print</span><span class="pun">(</span><span class="str">'Hello'</span><span class="pun">)</span> <span class="kwd">print</span><span class="pun">(</span><span class="str">"x = {}"</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">x</span><span class="pun">))</span> |
zwracany wynik to
1 2 |
<span class="typ">Hello</span> <span class="pln">x </span><span class="pun">=</span> <span class="kwd">None</span> |
Widać więc, że print (chociaż głównie kojarzy nam się z robieniem czegoś – wyświetlaniem napisu) jest też expression, bo ma wartość None.
Trochę inaczej jest tu:
1 2 |
<span class="pln">x </span><span class="pun">=</span> <span class="kwd">pass</span> <span class="kwd">print</span><span class="pun">(</span><span class="str">"x = {}"</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">x</span><span class="pun">))</span> |
oto wynik:
1 2 3 4 |
<span class="typ">File</span> <span class="str">"C:/temp/tests.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">18</span> <span class="pln"> x </span><span class="pun">=</span> <span class="kwd">pass</span> <span class="pun">^</span> <span class="typ">SyntaxError</span><span class="pun">:</span><span class="pln"> invalid syntax</span> |
Niestety – pass tylko coś robi (dokładniej rzecz biorąc „robi nic”), kompletnie nic nie zwraca, nawet None (!!!!)
Podobnie jest z przypisaniem:
1 2 |
<span class="pln">x </span><span class="pun">=</span> <span class="pun">(</span><span class="pln">y</span><span class="pun">=</span><span class="lit">6</span><span class="pun">)</span> <span class="kwd">print</span><span class="pun">(</span><span class="str">"x = {}"</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">x</span><span class="pun">))</span> |
też błąd:
1 2 3 4 |
<span class="typ">File</span> <span class="str">"C:/temp/tests.py"</span><span class="pun">,</span><span class="pln"> line </span><span class="lit">21</span> <span class="pln"> x </span><span class="pun">=</span> <span class="pun">(</span><span class="pln">y</span><span class="pun">=</span><span class="lit">6</span><span class="pun">)</span> <span class="pun">^</span> <span class="typ">SyntaxError</span><span class="pun">:</span><span class="pln"> invalid syntax</span> |
Przypisanie się wykonuje, ale podobnie jak poprzednio kompletnie nic nie zwraca.
No i po tym wstępie mogę tłumaczyć dlaczego nie zadziałało if 🙂
Wyrażenie if zapisane w postaci jednolinijkowca musi być wyrażeniem. Pierwsze polecenie:
print(price-bonus) if bonus_granted else price = 200
nie jest wyrażeniem, bo o ile jeszcze print coś zwraca (None), o tyle druga część z przypisaniem nic nie zwraca. Stąd błąd
Podobnie będzie tu:
print(price-bonus) if bonus_granted else pass
Ale za to tutaj już tego problemu nie ma, bo tu zawsze uzyskasz wyrażenie:
1 |
<span class="kwd">print</span><span class="pun">(</span><span class="pln">price</span><span class="pun">-</span><span class="pln">bonus</span><span class="pun">)</span> <span class="kwd">if</span><span class="pln"> bonus_granted </span><span class="kwd">else</span> <span class="kwd">print</span><span class="pun">(</span><span class="pln">price</span><span class="pun">)</span> |
Co ciekawe, jeśli wynik tego wyrażenia chcesz zapisać w zmiennej:
1 2 |
<span class="pln">x </span><span class="pun">=</span> <span class="kwd">print</span><span class="pun">(</span><span class="pln">price</span><span class="pun">-</span><span class="pln">bonus</span><span class="pun">)</span> <span class="kwd">if</span><span class="pln"> bonus_granted </span><span class="kwd">else</span> <span class="kwd">print</span><span class="pun">(</span><span class="pln">price</span><span class="pun">)</span> <span class="kwd">print</span><span class="pun">(</span><span class="str">"x = {}"</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">x</span><span class="pun">))</span> |
to okaże się, że jej wartość to None:
1 2 |
<span class="lit">9</span> <span class="pln">x </span><span class="pun">=</span> <span class="kwd">None</span> |
Więcej na ten temat można poczytać też tu (j.ang):
Mam nadzieję, że udało mi się rozwiać wątpliwości