Python 程式設計

第 3 章    Python 的資料

(1) 資料值與資料型態

∗ 資料值 (Value)

▸ 資料值是程式處理的基礎項目之一

▸ 例如:整數 5 或字串 'Hello world'

∗ 資料型態 (Data type) :不同的資料值分屬於不同的資料型態

▸ 整數(Integer):例如 5

▸ 浮點數 (Floating point, Float):例如 3.2

✶ 亦即「實數」,因小數點可以浮動,因此稱為浮點數,例如:
3.2 x 102 = 0.32 x 103 = 32 x 101

▸ 字串 (String):由一連串的字元組成,並且由兩個單引號或雙引號所包含, 例如 'Hello world'

▸ 布林 (Boolean):只有兩個值,「真」(True) 與「偽」(False)

▸ 物件 (Object):由許多資料及函式構成

∗ 可利用 type() 函式來顯示資料型態:

-->   建立 python/ch3 目錄, 在其中建立 datatype.py 程式檔,輸入以下內容並執行:

print(type('Hello world'))
print(type(17))
print(type(3.2))

結果:

<class 'str'>     --> 資料型態屬於字串類別 (String class)
<class 'int'>     --> 整數類別 (Integer class)
<class 'float'>   --> 浮點數類別 (Float class)

(2) 字串

∗ 字串 (String)

▸ Python的字串是由一對單引號或雙引號所包住一連串的字元,例如: 'Hello world', '17', '3.2', "這是一個字串", '這也是一個字串', ...

▸ 使用雙引號的字串中可以包含單引號,如 "Bruce's beard",而使用單引號的字串中可以包含雙引號,如 'I like the book "How to think like a computer scientist"'

▸ 字串通常使用單引號:因為輸入方便,看來較簡潔

▸ 跨行字串則使用三個單引號或雙引號,例如在 datetype.py 最後加入下列內容:

...
print(type(3.2))
print('''這個訊息將
跨越
許多行''')
print()
print("""這個訊息也
跨越
許多行""")

...
這個訊息將
跨越
許多行

這個訊息也
跨越
許多行

(3) 資料型態轉換

∗ 數值型態轉換與字串轉換

▸ Python 提供型態轉換 (Type conversion) 函式:int(), float(), str()

int():將傳入之參數轉為整數,若參數為浮點數則將小數捨去 (Truncate)

✶ 例如:建立 ch3/convert.py 檔案,內容如下:
print(3.14, int(3.14))
print(3.9999, int(3.9999))
print(3.0, int(3.0))
print(-3.999, int(-3.999))
print('2345', int('2345'))
print(int('23 瓶飲料'))
✶ 執行結果:
3.14 3      -->   浮點數 3.14 被轉成整數 3
3.9999 3      -->   浮點數 3.9999 被轉成整數 3
3.0 3      -->   浮點數 3.0 被轉成整數 3
-3.999 -3      -->   浮點數 -3.9999 被轉成整數 -3
2345 2345      -->   字串 '2345' 被轉成整數 2345
Traceback (most recent call last):
  File "<...>	/python/ch3/convertint.py", line 6, in <module>	
    print(int("23 瓶飲料"))
ValueError: invalid literal for int() with base 10: '23 瓶飲料'
--> 字串 '23 瓶飲料' 無法轉成整數,程式當掉並出現錯誤訊息。 因此,要將一個字串正確轉為整數,該字串必須是語法正確的數字字串

float():將傳入之參數轉為浮點數

✶ 例如:在 convert.py 中刪除最後一行錯誤指令並加上以下內容:
...
print('2345', int('2345'))
print(int('23 瓶飲料'))
print(float('123.45'))
print(type(float('123.45')))
print(float('123.45 元'))
✶ 執行結果:
123.45    -->   數值字串 '123.45' 被轉成浮點數 123.45
<class 'float'>   -->   資料型態為 float 類別
Traceback (most recent call last):
  File ".../python/ch3/convert.py", line 8, in <module>	
    print(float('123.45 元'))
ValueError: could not convert string to float: '123.45 元'
  --> 字串 '123.45 元' 無法轉成浮點數,程式當掉並出現錯誤訊息。因此, 要將一個字串正確轉為浮點數,該字串必須是語法正確的數字字串

str():將傳入之參數轉為字串

✶ 例如:在 convert.py 刪除最後一行錯誤指令並加上以下內容:
...
print(type(float('123.45')))
print(float('123.45 元'))
print(str(17))
print(str(123.45))
print(type(str(123.45)))
✶ 執行結果:
17   -->   數字 17 被轉成字串 '17'
123.45   -->   數字 123.45 被轉成字串 '123.45'
<class 'str'>   -->   資料型態為 str 類別

∗ 四捨五入與絕對值運算

round():四捨五入轉整數運算

✶ 例如:在 convert.py 後面加上:
...
print(type(str(123.45)))
print(3.14, round(3.14))
print(3.72, round(3.72))
結果:
3.14 3   -->   數字 3.14 被轉成 3
3.72 4   -->   數字 3.72 被轉成 4

abs():取絕對值 (Absolute value)

✶ 例如:在 convert.py 後面加上:
...
print(3.72, round(3.72))
print(abs(10-2), abs(2-10))
結果:8 8

(4) 變數

∗ 名稱 (Name):程式的重要元素之一

▸ 程式中的各種名稱統稱為識別字 (Identifier),包含模組名稱 (例如 convert.py) 、函式名稱 (例如 print()) 、或變數名稱 (例如 address) 等

▸ Python 識別字的規則:以英文字母或底線開頭,之後可以接字母、數字、或底線,例如: phone, mobile_phone, mobilePhone, mobilePhone2, ...

▸ 識別字的英文字母大小寫有別 (Case-sensitive) ,因此 address,Address, aDDress, 及 ADDRESS 均為不同的識別字

▸ Python 保留字 (Keyword) 如下,不可用於一般識別字:

False      await      else       import     pass
None       break      except     in         raise
True       class      finally    is         return
and        continue   for        lambda     try
as         def        from       nonlocal   while
assert     del        global     not        with
async      elif       if         or         yield

▸ Python 內建函式 (Built-in functions) 如下,若用來當作識別字,內建函式的功能將喪失,盡量不要使用:

abs()            delattr()      hash()          memoryview()    set()
all()            dict()         help()          min()           setattr()
any()            dir()          hex()           next()          slice()
ascii()          divmod()       id()            object()        sorted()
bin()            enumerate()    input()         oct()           staticmethod()
bool()           eval()         int()           open()          str()
breakpoint()     exec()         isinstance()    ord()           sum()
bytearray()      filter()       issubclass()    pow()           super()
bytes()          float()        iter()          print()         tuple()
callable()       format()       len()           property()      type()
chr()            frozenset()    list()          range()         vars()
classmethod()    getattr()      locals()        repr()          zip()
compile()        globals()      map()           reversed()      __import__()
complex()        hasattr()      max()           round()  

∗ 變數 (Variable)

▸ 變數:代表一個數值的名稱

▸ 指派指令 (Assignment instruction) 可以建立新的變數,並設定其值,語法如下:

<variable> = <expr>
<variable> :變數名稱,是一個識別字
<expr> :表示式,可以是一個值或一個運算式
✶ 例如下圖 ,指派指令將變數指向物件
message = '近來可好?'
pi = 3.14
numStudents = 57
Variable.png

▸ Python 變數的特性

✶ 不需要事先宣告,利用指派指令直接創造新變數
✶ 動態資料型別,只要指派指令表示式的資料型態改變,變數的資料型態就改變,例如以下變數 a 可以是整數、浮點數、或是字串
a = 10        # 整數
a = 3.2       # 浮點數 (原先參考到 10 的指標被刪除)
a = 'abcd'    # 字串 (原先參考到 3.2 的指標被刪除)
Variable2.png

▸ 常用的變數名稱格式

✶ 底線式 (以底線結合許多字),例如:number_of_students
✶ 駝峰式 (首字開頭小寫,其餘字開頭大寫),例如:numberOfStudents

▸ 註:許多其他程式語言需要事先宣告變數及其資料型態,例如 Java:

int students;
students = 57;

(5) 資料儲存的特性

∗ 靜態型別與動態型別程式語言

▸ 靜態型別 (Static typing):變數要先宣告,宣告時需要指定變數的資料型態,且該型態不會改變,例如:Java, C, ...

✶ Java 範例:
int x;
x = 'abcd';    // Compilation error

▸ 動態型別 (Dynamic typing):變數不需要先宣告,變數的資料型態隨時可改變,例如:Python, JavaScript, PHP, ...

✶ Python 範例:
x = 3
x = 'abcd'    # OK

∗ 變數與記憶體

▸ 靜態型別語言的變數與記憶體是位置的關係,每個變數有固定的儲存空間,在宣告時決定,因此資料型態無法改變,例如 Java:

int width = 20;
int height = 30;
boolean isWall = true;
boolean canPaint = true;
javaVariable.png

▸ 動態型別語言的變數與記憶體是指標的關係,每個變數會參考 (Reference) 記憶體裡的一個值,多個變數可以參考同一值,例如 Python :

width = 20
height = 20
isWall = True
canPaint = True
pythonVariable.png

∗ 強型別與弱型別

▸ 強型別 (Strong typing):運算子期待變數應有某種資料型別,若使用其他型別會造成錯誤,例如:

✶ Java:
int x;
x = 20 + 'abcd';    // Compilation error
✶ Python:
x = 20 + 'abcd';    # Interpretation error

▸ 弱型別 (Weak typing):運算子期待變數應有某種資料型別,若使用其他型別可能不會造成錯誤,例如:

✶ JavaScript:
x = 20 + 'abcd';    // x: '20abcd'
✶ PHP:
$x = 20 + 'abcd';   # $x: '20abcd'

∗ 型態強迫轉換 (Type coercion)

▸ 例如 JavaScript:如果使用並不期待的資料型態, JavaScript 會嘗試解決型態問題,而不是直接發生發佈錯誤訊息, 亦即 JavaScript 會在幕後進行資料型態轉換,稱為型態強迫轉換 (Type coercion) ,例如:

'1' > 0   --> true (將字串 '1' 轉為數值)
x = 5 + '2'   --> '52' (相加:將數值轉字串)
x = 5 - '2'   --> 3 (相減:將字串轉數值)

▸ Python 不會強迫轉換變數型態

∗ 電腦算術的限制

▸ 一般程式語言以固定大小的位元數儲存整數

✶ 32 位元之整數範圍:-231 ~ 231-1
✶ 64 位元之整數範圍:-263 ~ 263-1
✶ 超過整數範圍的計算會使程式編譯失敗、執行當掉、或者算出錯誤的結果

Python 的整數並無範圍,唯一的限制是電腦裡所擁有的記憶體的量

✶ 當整數數值不大時, Python 使用一般的整數表示法
✶ 當整數數值很大時, Python 使用更多位元來表示
✶ 大整數運算時, Python 則將運算拆成幾部分來算,故效率較低
✶ 試試看,將兩個 非常大 的整數相乘

(6) 運算子與運算元

∗ 運算子 (Operator)

▸ 運算的符號,例如加、減、乘、及除的運算子分別為 +, -, *, /

∗ 運算元 (Operand)

▸ 運算子所運算的值,例如以下的 ab 是運算元

x = a + b

∗ Python 3 的除法有兩種運算子:/ 與 //

/:一般除法,相除的結果一定是浮點數

x = 5
y = 2
print(x/y)    # 2.5
x = 6
y = 2
print(x/y)    # 3.0

//:整除法,相除結果僅留整數部份 (如果兩個運算元均為整數,則結果是整數, 若某一個運算元是浮點數,則是浮點數)

x = 5
y = 2
print(x//y)    # 2
x = 5.0
y = 2
print(x//y)    # 2.0

∗ 其他語言的除法可能會因為運算元的資料型態不同而產生不同結果,例如 Java:

▸ 兩個運算元都是整數:

int x, y;
x = 5;
y = x/2;    // y: 2

▸ 有一個運算元是浮點數 (另一個整數變數會自動提昇為浮點數):

int x;
float y;
x = 5;
y = x/2;    // y: 2.5

∗ 模數運算子 (Modulus operator)

▸ 亦稱為餘數運算子 (Remainder operator) 或整數餘數運算 (Integer remainder operator)

▸ 計算兩個整數相除後的餘數,例如:

remainder = 7 % 3
print(remainder)    # remainder: 1

▸ 模數運算常用在判斷某個整數是否為另一個整數的倍數 (亦即兩個數值是否能整除)

✶ 例如,如果 x % y 等於 0 (餘數等於 0 ),則 xy 的倍數,亦即 x 能被 y 整除

▸ 範例:給定總秒數,計算一般格式的時、分、秒數 (分及秒都小於 60 )

✶ 建立 ch3/time.py 檔案,內容如下:
totalSeconds = 7684

hours = totalSeconds // (60*60)
remainingSeconds = totalSeconds % (60*60)

minutes = remainingSeconds // 60
seconds = remainingSeconds % 60

print(hours, '時', minutes, '分', seconds, '秒')
2 時 8 分 4 秒

▸ 註:以上列印字串的方式很麻煩,Python 3.6 提出了 F-string (Format string) 的語法:

✶ 所有資料可以僅寫成一個字串,並在前面加上 f 字母
✶ 變數以大括號包住放在字串裡,大括號裡也可以有表示式,例如:
print(f'{hours} 時,{minutes} 分,{seconds} 秒')
print(f'折扣後總價格:$NT {price*0.9}')

▸ 練習 3-1

∗ 次方運算子 (Power operator)

▸ 計算數值的指數次方,例如:

x = 7**2
print(x)    # x: 49

▸ 練習 3-2

(7) 輸入指令

input() 函式: Python 的輸入函式,讓使用者從鍵盤輸入資料

✶ 上述 time.py 程式有點侷限,因為總秒數都是寫死的,無法針對不同的總秒數來重複計算, 解決方案:讓使用者輸入總秒數
✶ 利用 input() 函式取得使用者輸入的資料,並將資料指派給變數 (使用者輸入的任何資料都是字串, 因此需要轉換為數值):

totalSeconds = 7684
totalSeconds = input('請輸入總秒數:')
totalSeconds = int(totalSeconds)

hours = totalSeconds // 3600
...

▸ 練習 3-3

(8) 運算順序

▸ 當表示式裡有許多運算子,哪些運算應該先執行,哪些運算應該後執行 ? 例如:

x = 2 * 3 + 4
✶ 若 2*3 先計算,結果為 10;若 3+4 先計算,結果為 14

▸ 運算的順序由運算子的優先順序法則 (Rule of precedence) 決定,優先權由高至低為:

1. 括號內的表示式
x = 2 * (3 + 4)    # 14
2. 次方
x = 2**3 + 4    # 12
3. 乘、除、及餘數
x = 2*3 + 4     # 10
4. 加減
x = 3**2*4 + 2    # 38

▸ 優先權相同的運算子,由左至右進行運算

x = 2*3/4    # 1.5

▸ 練習 3-4

(9) 簡潔的指派指令

▸ 以原先的變數值進行更新:

x = x + 1     -->    x += 1
x = x - 1     -->    x -= 1
x = x * 2     -->    x *= 2
x = x / 2     -->    x /= 2
x = x % 2     -->    x %= 2
x = x // 2    -->    x //= 2
x = x ** 2    -->    x **= 2

▸ 同時設定多個變數值:

x = y = z = 5        # 相同值
x, y, z = 3, 4, 5    # 不同值
x, y = y, x          # 交換值

上一章       下一章