弱型別 & 強型別

Python 是弱型別語言,變數的型別在執行時才決定。所以你可以反覆橫跳也不會報錯:

1
2
x = 10  # x 是整數
x = "Hello" # 現在 x 變成字串,大丈夫,不會報錯

但強型別的 C 就不行了,你要先宣告。

然而弱型別會讓效率差一點。你變數換來換去,表面上很方便,其實底層依舊有在幫你找新的地址來存東西,只是你不用自己操心。

為什麼 C 至今依舊不敗?就是因為底層的東西我們自己操心,自己操作,雖然難寫,但可控性更高。

Python 自有一套記憶體管理術

比如說:

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> a = "hey"
>>> id(a)
4380090864
>>> a = 10
>>> id(a)
4377258576
>>> b = a
>>> id(b)
4377258576
>>> c = "hey"
>>> id(c)
4380090800

當我賦值 b 跟 a 一樣,Python 就指向同一個位置,很省哦。但 C 語言中,就算兩個變數的賦值一樣,依然會分別存在兩個不同的位置。

好幾步之後,我們突然賦值 c (此處指上述程式碼中的變數c,不是C語言)為 “hey”,Python 還記得這個 “hey” 其實前面有人用過,反正記憶體也還沒把這個資料洗掉(還沒內存回收),你 c 就繼續用這個位置吧!可見,Python 自有一套記憶體管理術,而我們使用者也不用太操心這些環節。

Character & String

C 內建字元型別 char,如果你不引用外部的 library(例如 string.h),就只能用 char 來拼湊字串。這很合理,字串是人類在看的,咱 C 是面向硬體的。

Python 完全相反,沒有字元型別,但原生自帶字串型別 str。這很合理,Python 是面向咱人類的。

Interpreter & Compiler

Python 是用 interpreter 直譯的,一句一句執行。

C 是用 compiler 編譯成執行檔才能執行。

遊戲引擎、嵌入式系統

很多遊戲引擎都是用C語言開發的,虛幻引擎、Unity就是用C++。

據悉(C 的老師說的),後續的效能優化是對組合語言慢慢刪減調整。

嵌入式系統也常用C開發,同樣的理由,因為較為底層,所以輕量且高效。

編譯順序

C的編譯器是按照順序編譯的。

函數(function)要寫在主函數(main)的前面,若是反過來,編譯器會不知道你在調用什麼。

printf 的處理順序

1
2
int i = 6;
printf("%d,%d,%d", i, i++, i++);

printf 位於 <stdio.h> 庫中。這段程式會輸出 8,7,6

p.s. i++ 是「後置遞增」,表示在當前語句完成後,i 的值會增加;++i 則是「前置遞增」,先增加再賦值。

至於原因,跟編譯器的處理方式有關,三個變數從左到右被放到 stack 裡面,所以最後出來的順序是反過來。如果遇到 i++ 就先賦值了,而如果遇到 ++i 則運算完後把指標指向目前的 i。

然而這句包含未定義的行為,很危險,我們應該避免同一句裡面對同一個參數做多次修改。我們如果改成這樣:

1
2
3
4
int i = 6;
printf("%d,", i);
printf("%d,", i++);
printf("%d", i++);

如此就會輸出 6,6,7

但如果:

1
2
int i = 6;
printf("%d,%d,%d", i, ++i, ++i);

你猜猜看會輸出什麼?輸出了 8,8,8,我暈。

算數運算子

C 跟 Python 裡面都有基本的 a+b, a-b, a*b, a/b, a%b,但其中 a/b 裡面 C 只給整數商,Python 會直接浮點送你小數點。

那 Python 要怎麼只拿整數商?必須寫作 a//b 才行。

另外 a**b 的指數運算 Python 有但 C 沒有。

算數賦值運算子

a = a + 5中的「+」就是算術運算子,「=」就是賦值運算子。

來咯,C++ 跟 Python 裡面都有這兩者的合體——「算數賦值運算子」。

剛剛的 a = a + 5 用算數指定運算子簡化成 a += 5。總之就是,先進行運算,接著直接賦值成運算後的結果。

return 0

C++裡面常看到return 0:

1
2
3
4
int main()
{
return 0;
}

函數執行完一定要返回一個0嗎?嗯,收到0代表這個函數執行完畢。

而且其實就算你忘了 return 0,現在編譯器也會自己幫你 return 0。

布林函數

C 沒有原生的布林函數,也就是他不認識 true 跟 false。但可以這樣玩:

1
2
3
4
if(0.1)
{
printf("不為0就為真");
}

會 print 出來。

三元運算子 (ternary operator)

1
printf("%d",(0)?1:2);

這裡因為括弧內為假,所以最後輸出「2」。

設條件居然還能不寫 if!C 真的很喜歡簡潔,但同時閱讀起來很不直觀。

喔其實 python 也有三元運算:

1
print("true" if 1 else "false")

邏輯運算子

Python 很貼心直接用自然語言的 and, or, not,而 C 分別是 &&, ||, !

位元運算子

C 底層到什麼程度呢?可以對位元進行操作。

1
printf("%d",13&7);

最後會得到「5」,因為我們對 13 跟 7 進行二進位的 AND 操作。

其他的還有 | for OR, ~ for not, ^ for XOR。

另外還能 <<n 就是左移位數(低位補零),其實就是乘以 2^n。反之就是 <<n

Python 當然就沒有這些玩法了。

Slicing

Python 獨有的 Slicing:

1
2
3
b = "Python rules!"
print(b[::1]) #輸出 Python rules!
print(b[::-1]) #輸出 !selur nohtyP

其中語法為 sequence[start:stop:step​​]。如果頭尾省略不寫的話,如果 step 為正,那就是開頭當做 start;若 step 為負,結尾當做 start。(如果 step 不寫的話,默認是 1)

居然在同一個語法自帶 if 判斷?好吧。

物件導向 Object-Oriented

1
2
3
b = "Python"
print(len(b)) #輸出 6
print(b.upper()) #輸出 PYTHON

作為物件導向的語言,在你創建了 b="Python" 之後,Python 就自己幫你維護了關於 b 這個物件的各種資訊跟方法。

例如 len(b) 是 b 這個 string 的長度。你有自己寫程式去進行判斷嗎?沒有,但這件事 Python 幫你維護好了。

例如 b.upper() 就是一個方法,只要你是 string,都可以調用這個方法來將字串裡面的字都轉成大寫。

1
print("XD"*10) #輸出 XDXDXDXDXDXDXDXDXDXD

你看連 string 的乘法都可以。

容器們:Tuple, List, Dictionary, Set

這些資料結構只有 Python 有。

特性 tuple list
可變性 不可變 可變
語法 小括號 () 方括號 []
方法數量 僅有 countindex 多數據操作方法(如 append
性能 更高效(因為不可變性) 相對低效
使用場景 用於靜態數據 用於動態數據

注意 tuple 如果只有一個元素時,必須加逗號:single_element_tuple = (1,)

解包 Unpacking

1
2
3
4
5
6
7
8
>>> tu = (('1','a'),('2','b'),('3','c'))
>>> for a,b in tu:
... print(a+'->'+b)
...
#輸出
#1->a
#2->b
#3->c

只要結構上大家能一一對應,通常 python 都能幫你兜在一起。

f-string

1
2
3
4
>>> name="Shuai"
>>> face="handsome"
>>> print(f"Hi, my name is {name}. I'm very {face}, as you can see.")
#輸出 Hi, my name is Shuai. I'm very handsome, as you can see.

很方便餒! 順帶一提,此例中的句子都是真人真事。

1
2
3
>>> pi=3.1415926
>>> print(f"pi= {pi:.2f}")
#輸出 pi= 3.14

當然啦,指定格式也是可以的。

1
2
3
4
>>> for i in range(5):
... print(f"{i}", end=" ")

#輸出 0 1 2 3 4

python 預設的 print 會幫你每次都換行(也就是 \n),怎麼自定義?用 f-string 可以指定 print 的結尾是什麼!

偷偷幫你換行

C 裡面你通常要自己透過 \n 來換行,不然大家就擠在同一行。

Python 不出意外地(?)很自動就幫你換行了,十分方便。但如果你今天不想換行的話,要特別跟他說一下,例如:

1
2
3
4
5
>>> print('hi'); print("hello")
hi
hello
>>> print('hi', end="不換行!"); print("hello")
hi不換行!hello

字元轉整數(char to int)

1
int a = '9'-'0';

這行是啥?其實就是 a=9,酷吧!不會報錯哦。

elif

大部分程式語言跟 C 一樣用 else if 作為條件判斷的語句。

就 python 跟大家不一樣用的是 elif

檢查是否完整執行 loop

1
2
3
4
5
6
>>> for i in range(10):
... print(f"{i}", end=" ")
... else:
... print("It's not broke, good!")
...
#輸出 0 1 2 3 4 5 6 7 8 9 It's not broke, good!

python 還拿了 else 來判斷 loop 是否有被 break

C 沒有類似的原生設計。

函數註解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> def hello():
... """
... This is a function which says hello to you!
... """
... print("hello!")
...
>>> hello()
hello!
>>> print(hello.__doc__)

This is a function which says hello to you!

>>> help(hello)
#他會打開同上的 doc

C 有這種事嗎?沒有。