iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 3
4
Software Development

活用python- 路遙知碼力,日久練成精系列 第 3

Day3 - 天啊我只有「螢幕十行」,python簡力救救我啊!

路遙知碼力,日久練成精-只要在程式之路鑽研的夠深,便能夠充分發揮程式碼的力量; 練習的日子夠久,便能夠練成寫出精簡代碼的能力。

大家好,我是心原一馬,內心原來一心喜歡打程式碼。

古有「一目十行」,比喻一個人閱讀速度很快。
電腦時代有「螢幕十行」,比喻電腦螢幕太小導致看程式很痛苦。
不知道讀者是否有寫過小型程式專案的經驗?
(學校修課寫約數百~一千行的程式期末專案也可以算)
看著幾百行的程式,
「螢幕十行」導致必須上下捲動螢幕才可以看到完整的程式碼,
常常無法連貫的釐清程式邏輯,
哪怕是要修改幾行程式,
都要把螢幕上下捲動個老半天才可以完成。

python能以很簡短的程式碼表達完整的功能,
應該有助於大大減少這種困擾。
以下來從基礎語法特性談談為什麼python可以比別的程式語言精簡:

到底python語法上精簡了什麼?

從HelloWorld說起

只要你學過任何一門程式語言,對HelloWorld一定不陌生。
HelloWorld通常是學任何一門程式語言的第一堂課- 「在螢幕上印出一行字- HelloWorld」
,象徵著你踏上學習程式的旅程了。
我們先來看一下C語言怎麼寫HelloWorld的:

#include <stdio.h>
int main()
{
    printf("Hello world!\n");
    return 0;
}

第一行是引入標準函式庫,讓我們可以使用printf()這個函數,
第二行的main()表示主程式,
第五行寫return 0表示程式正常結束。

還沒完,我們再看java版的,疑惑應該更多一些:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello! World!");
    }
}

一下子看到好幾個不懂的關鍵字,
public, class, static, void
依稀可以了解System.out.println("Hello! World!");這一行就是在螢幕上印出"Hello! World!",

這時新手可能就會疑惑了,
怎麼只是要在螢幕上印出一行字搞的那麼複雜?
正巧,小馬的疑惑也和大家一樣,
python的HelloWorld 一行即可:

print("HelloWorld")

而且函數名稱應該也是最符合英文的,
就直接印出HelloWorld,可說是非常直覺。
以下開始盤點python幾個跟其它程式語言很不一樣的特性。

特性一: 省去main()主程式函數

通常多數程式語言會有類似C的main()函數來表示這是主程式,
程式一定是從main()開始執行。
在python裡面直接省略掉這樣麻煩的語法。

特性二: 一句話的結束不必加分號

在多數程式語言中,
每行程式敘述的後面都會加上一個分號(;)
,表示一個句字的結束。
記得我初學C程式的時候,
也是很多同學常常容易忘記加分號。
不過既然每行程式後面都要加分號,
在python程式裡也直接省去了加分號的麻煩。
事實上,python非常人性化,
你加不加分號程式都可以執行。
例如這支程式(不加分號)可以執行:

print("HelloWorld")

這支程式(加分號)也可以執行:

print("HelloWorld");

特性三: 以縮排區分程式碼內外區域

多數程式語言會加大括號區分程式的內外,對於縮排則沒有嚴格的要求,例如以下這隻簡單的C程式:

#include <stdio.h>

int main()
{
    int x=3;
    int y=1;
    if(x==3)
    {
        printf("x=3\n");
        y=5;
    }
    printf("y=%d\n",y);
}

在這支C程式中,
我們希望在x等於3時,
執行兩個指令: 「印出x=3」及「把y的值改為5」,
因此用大括號把這兩個指令包起來。
但是當程式很多層時,很多大括號會使程式篇幅看起來很大。
在python裡,直接利用縮排(if區塊內程式空四行)區分程式內外:

# python程式
x, y =3, 1
if x==3:
    print("x=3")
    y=5
print("y=",y)

有沒有感覺python程式體積就是小很多?
疑疑?從其它語言轉python的朋友會覺得這邊出現了x, y =3, 1這樣神奇的語法?
讓我們繼續看下去。

特性四: 變數不必先宣告型態

在很多程式語言中,
宣告變數必須事先宣告它是什麼型別(int, float, string,…)。
而python語言不同,
可以直接給變數賦值,
我們用內建函數type()來檢查一個變數的型態。

s=2
print(type(s))
s= "python"
print(type(s))

結果為
<class 'int'>
<class 'str'>
像這樣,一開始先把s的值設成2,它的型態就是int,
之後再把s設成"python",它的型態就是str(字串)。
程式執行的過程可以自由更改變數型態。
另外,像是python的list內部也可以容納不同型態的變數,
例如:

myList=[True, "abc", 50, 6.3, [1,2,5]] 

同時在list內部放了bool值、字串、整數、浮點數,
甚至再放一個list都是OK的。
這種寫法大大的增加了編程的自由。

特性五: 可一次修改多個變數的值

在很多程式語言中,都是一行才能修改一個變數的值,
例如C語言如果想要分別把三個變數改為1,2,3,
就必須要寫三行:

//C程式
int x,y,z;
x=1;
y=2;
z=3;

但若在python中,可以一行解決:

# python程式
x,y,z=1,2,3

這樣簡潔的方法帶來了一些好處:

範例3-1: 交換兩個變數a,b的值

在C語言中,如果想要交換兩個變數的值,
我們常常會用一個變數暫存(假設一開始a,b的值分別是3,5):

int a=3, b=5; 
int temp=a;
a=b;
b=temp;

注意不能直接寫

a=b;
b=a;

因為做完a=b;這行時,原本a的值即被覆蓋掉,變成5,
再做b=a;時,b的值還是5,不會換成a的值。

但python可以一次給多個變數賦值,
便不需要透過temp變數來暫存,
直覺的交換a,b即可:

a,b=b,a

特性六: 所有變數名稱其實就像c的指標

小馬今天不打算花長篇大論解說「指標」是什麼,
如果你學了C/C++的指標讓你覺得頭昏腦脹,
你可以試著聽看看小馬獨創的「貼標籤」解說,
直接看python程式碼例子:

範例3-2: 誰偷吃了我的蛋糕?

我們用fridge這個變數表示冰箱,
裡面存放字串當做是冰箱裡面的東西,

fridge = ['蛋糕', '蘋果', '香蕉']
b = fridge
b.remove('蛋糕')
print("列表b的內容為:", b)
print("列表fridge的內容為:", fridge)

首先會印出列表b的內容為: ['蘋果', '香蕉']
來來,你猜猜下一行的結果是什麼?

出乎意料的,結果居然印出了列表fridge的內容為: ['蘋果', '香蕉']?
太神奇了,
本來我們不是期望做了b = fridge後,
兩個變數是不同的列表嗎?

我們可以這樣想,
其實每個變數名稱都像「標籤」一樣,
['蛋糕', '蘋果', '香蕉']是裝有三個字串的列表,
上面貼了一張 fridge的標籤表示它是冰箱,

https://ithelp.ithome.com.tw/upload/images/20190907/20117114t2uldLT9uS.png

這時候,你的室友B也在交誼廳的冰箱貼了一張名字為「b」的標籤,
這時總共還是只有一個冰箱而已,

https://ithelp.ithome.com.tw/upload/images/20190907/20117114JxNq9WX6pr.png

這時,你室友把貼上「b」的標籤的冰箱裡的蛋糕吃掉了,
那貼上fridge的標籤的冰箱的冰箱裡的蛋糕當然也沒了。
(廢話~ 是同一個冰箱嘛~ 如圖示)
https://ithelp.ithome.com.tw/upload/images/20190907/20117114LJe9UrOxuz.png

範例3-3: 貼到別的冰箱

我們看一段類似的程式碼:

fridge = ['蛋糕', '蘋果', '香蕉']
b = fridge
b = ['蘋果', '香蕉']
print("列表b的內容為:", b)
print("列表fridge的內容為:", fridge)

結果為:
列表b的內容為: ['蘋果', '香蕉']
列表fridge的內容為: ['蛋糕', '蘋果', '香蕉']

你可以這樣想,在python中用=做變數賦值的時候,
可以想成是把等號右邊代表的物件貼上等號左邊變數名字的標籤,
因此做b = ['蘋果', '香蕉']時,
其實是把b這張標籤貼到另一個冰箱了,如圖示:

https://ithelp.ithome.com.tw/upload/images/20190907/20117114OAfhgrrHKk.png
原本的fridge 便不受影響。

那那…究竟如何真的複製一個冰箱呢?

我們希望有這樣的效果:
https://ithelp.ithome.com.tw/upload/images/20190907/20117114Y0WSytaFqw.png

也就是希fridge和b真的是不同列表,
不論更改哪一個都不會影響另一個值。
其實很簡單,把範例3-2程式的
b = fridge改成
b = fridge[:]就好,
如下:

fridge = ['蛋糕', '蘋果', '香蕉']
b = fridge[:]
b.remove('蛋糕')
print("列表b的內容為:", b)
print("列表fridge的內容為:", fridge)

結果為:
列表b的內容為: ['蘋果', '香蕉']
列表fridge的內容為: ['蛋糕', '蘋果', '香蕉']
這次更改b真的沒有影響到fridge了。

伏筆?

等等啊,小馬老師,現在我還有很多東西不懂啊?

  • 你剛剛寫的b = fridge[:]為什麼可以這樣寫?
  • 你在Day1秀的那個三行程式變一行的那個魔法
L=[i for i in range(1,101)]

又是怎麼回事呢?

  • 一直在學python語法,好像還沒看到python特別出色的地方啊?

哈哈,看來小馬好像挖了一些坑呢,
正所謂「台上一行code,台下十年功」,
很多內容一時半刻無法點明,
但最後一定把這些坑補齊。
先透漏兩個關鍵字「切片」、「列表生成式」,
傳說中python語法中的屠龍寶刀,
此刃一出,許多又臭又長的程式碼瞬間退散。

現在是Day3,你,
有勇氣閱到最後嗎?


上一篇
Day2 – 鐵人賽既出,駟馬難追,來學習python特性吧
下一篇
Day4- Python內建函數是你的好夥伴,認識max(), min(), len(),sorted(),sum(),abs(), pow()
系列文
活用python- 路遙知碼力,日久練成精30

尚未有邦友留言

立即登入留言