2024年6月16日 Python - 基礎

流星<。)#)))≦發表於2024-06-17

基礎語法

編碼

預設情況下,Python 3 原始碼檔案以 UTF-8 編碼,所有字串都是 unicode 字串。 當然你也可以為原始碼檔案指定不同的編碼:

# -*- coding: cp-1252 -*-

識別符號

  • 第一個字元必須是字母表中字母或下劃線 _
  • 識別符號的其他的部分由字母、數字和下劃線組成
  • 識別符號對大小寫敏感

在 Python 3 中,可以用中文作為變數名,非 ASCII 識別符號也是允許的

Python 保留字

保留字即關鍵字,我們不能把它們用作任何識別符號名稱。Python 的標準庫提供了一個 keyword 模組,可以輸出當前版本的所有關鍵字:

>>> import keyword
>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

註釋

Python 中單行註釋以 # 開頭

多行註釋可以用多個 # 號,還有 '''"""

#!/usr/bin/python3

# 第一個註釋
# 第二個註釋

'''
第三個註釋
第四個註釋
'''

"""
第五個註釋
第六個註釋
"""
print("Hello, Python!")

行與縮排

Python 最具特色的就是使用縮排來表示程式碼塊,不使用大括號 {}

縮排的空格數是可變的,但是同一個程式碼塊的語句必須包含相同的縮排空格數。

以下程式碼最後一行語句縮排數的空格數不一致,會導致執行錯誤:

if True:
    print("Answer")
    print("True")
else:
    print("Answer")
  print("False")  # 縮排不一致,會導致執行錯誤

報錯資訊:

IndentationError: unindent does not match any outer indentation level

多行語句

Python 通常是一行寫完一條語句,但如果語句很長,我們可以使用反斜槓 \ 來實現多行語句

[] , {} , 或 () 中的多行語句,不需要使用反斜槓 \

total = item_one + \
        item_two + \
        item_three

total = ['item_one', 'item_two', 'item_three',
         'item_four', 'item_five']

空行

函式之間或類的方法之間用空行分隔,表示一段新的程式碼的開始。類和函式入口之間也用一行空行分隔,以突出函式入口的開始。

空行與程式碼縮排不同,空行並不是 Python 語法的一部分。書寫時不插入空行,Python 直譯器執行也不會出錯。但是空行的作用在於分隔兩段不同功能或含義的程式碼,便於日後程式碼的維護或重構。

記住:空行也是程式程式碼的一部分。

同一行使用多條語句

Python 可以在同一行中使用多條語句,語句之間使用分號 ; 分割

#!/usr/bin/python3

import sys; x = 'runoob'; sys.stdout.write(x + '\n')

使用互動式命令列執行,輸出結果為:

>>> import sys; x = 'runoob'; sys.stdout.write(x + '\n')
runoob
7

此處的 7 表示字元數,runoob 有 6 個字元,\n 表示一個字元,加起來 7 個字元。

多個語句構成程式碼組

縮排相同的一組語句構成一個程式碼塊,我們稱之 程式碼組

ifwhiledefclass 這樣的複合語句,首行以關鍵字開始,以冒號 : 結束,該行之後的一行或多行程式碼構成程式碼組

我們將首行及後面的程式碼組稱為一個 子句(clause)

多個變數賦值

a = b = c = 1
a, b, c = 1, 2, "runoob"

Python3 直譯器

Linux/Unix的系統上,一般預設的 python 版本為 2.x,我們可以將 python3.x 安裝在 /usr/local/python3 目錄中。

安裝完成後,我們可以將路徑 /usr/local/python3/bin 新增到您的 Linux/Unix 作業系統的環境變數中,這樣您就可以透過 shell 終端輸入下面的命令來啟動 Python3

$ PATH=$PATH:/usr/local/python3/bin/python3    # 設定環境變數
$ python3 --version
Python 3.4.0

在 Window 系統下你可以透過以下命令來設定 Python 的環境變數,假設你的 Python 安裝在 C:\Python34 下:

set path=%path%;C:\python34

互動式程式設計

Linux 下:

$ python3
Python 3.6.8 (default, Apr 19 2021, 17:20:37) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux

Windows 下:

> python
Python 3.10.1 (tags/v3.10.1:2cd268a, Dec  6 2021, 19:10:37) [MSC v.1929 64 bit (AMD64)] on win32

指令碼式程式設計

透過以下命令執行該指令碼:

$ python3 hello.py

在 Linux/Unix 系統中,你可以在指令碼頂部新增以下命令讓 Python 指令碼可以像 SHELL 指令碼一樣可直接執行:

#! /usr/bin/env python3

然後修改指令碼許可權,使其有執行許可權,命令如下:

$ chmod +x hello.py

執行以下命令:

./hello.py

運算子

Python 語言支援以下型別的運算子:

  • 算術運算子
  • 比較(關係)運算子
  • 賦值運算子
  • 邏輯運算子
  • 位運算子
  • 成員運算子
  • 身份運算子
  • 運算子優先順序

算術運算子

以下假設變數 a=10 ,變數 b=21

運算子 描述 例項
+ 加 - 兩個物件相加 a + b 輸出結果 31
- 減 - 得到負數或是一個數減去另一個數 a - b 輸出結果 -11
* 乘 - 兩個數相乘或是返回一個被重複若干次的字串 a * b 輸出結果 210
/ 除 - x 除以 y b / a 輸出結果 2.1
% 取模 - 返回除法的餘數 b % a 輸出結果 1
** 冪 - 返回x的y次冪 a**b 為 10 的21次方
// 取整除 - 向下取接近商的整數 >>> 9//2 4
>>> -9//2 -5
#!/usr/bin/python3

a = 21
b = 10
c = 0

print("a 的值位:", a)  # 21
print("b 的值位:", b)  # 10

c = a + b
print("a + b 的值為:", c)  # 31

c = a - b
print("a - b 的值為:", c)  # 11

c = a * b
print("a * b 的值為:", c)  # 210

c = a / b
print("a / b 的值為:", c)  # 2.1

c = a % b
print("a % b 的值為:", c)  # 1

# 修改變數 a 、b 、c
a = 2
b = 3
c = a ** b
print("a ** b 的值為:", c)  # 8

a = 10
b = 5
c = a // b
print("a // b 的值為:", c)  # 2

比較運算子

以下假設變數 a 為 10 ,變數 b 為 20 :

運算子 描述 例項
== 等於 - 比較物件是否相等 (a == b) 返回 False
!= 不等於 - 比較兩個物件是否不相等 (a != b) 返回 True
> 大於 - 返回 x 是否大於 y (a > b) 返回 False
< 小於 - 返回 x 是否小於 y 。所有比較運算子返回 1 表示真,返回0表示假。這分別與特殊的變數 True 和 False 等價。注意,這些變數名的大寫。 (a < b) 返回 True
>= 大於等於 - 返回 x 是否大於等於 y (a >= b) 返回 False
<= 小於等於 - 返回 x 是否小於等於 y (a <= b) 返回 True

賦值運算子

以下假設變數 a 為 10 ,變數 b 為 20 :

運算子 描述 例項
= 簡單的賦值運算子 c = a + b 將 a + b 的運算結果賦值為 c
+= 加法賦值運算子 c += a 等效於 c = c + a
-= 減法賦值運算子 c -= a 等效於 c = c - a
*= 乘法賦值運算子 c *= a 等效於 c = c * a
/= 除法賦值運算子 c /= a 等效於 c = c / a
%= 取模賦值運算子 c %= a 等效於 c = c % a
**= 冪賦值運算子 c **= a 等效於 c = c ** a
//= 取整除賦值運算子 c //= a 等效於 c = c // a
:= 海象運算子,可在表示式內部為變數賦值。Python3.8 版本新增運算子 在這個示例中,賦值表示式可以避免呼叫 len() 兩次:
if (n := len(a)) > 10: print(f"List is too long ({n} elements, expected <= 10)")

位運算子

按位運算子是把數字看作二進位制來進行計算的。Python中的按位運演算法則如下:

下表中變數 a 為 60,b 為 13二進位制格式如下:

a = 0011 1100

b = 0000 1101

-----------------

a&b = 0000 1100

a|b = 0011 1101

a^b = 0011 0001

~a  = 1100 0011
運算子 描述 例項
& 按位與運算子:參與運算的兩個值,如果兩個相應位都為 1 ,則該位的結果為 1 ,否則為 0 (a & b) 輸出結果 12 ,二進位制解釋: 0000 1100
| 按位或運算子:只要對應的二個二進位有一個為 1 時,結果位就為 1 (a | b) 輸出結果 61 ,二進位制解釋: 0011 1101
^ 按位異或運算子:當兩對應的二進位相異時,結果為 1 (a ^ b) 輸出結果 49 ,二進位制解釋: 0011 0001
~ 按位取反運算子:對資料的每個二進位制位取反,即把 1 變為 0 ,把 0 變為 1。~x 類似於 -x-1 (~a) 輸出結果 -61 ,二進位制解釋: 1100 0011, 在一個有符號二進位制數的補碼形式。
<< 左移動運算子:運算數的各二進位全部左移若干位,由 << 右邊的數指定移動的位數,高位丟棄,低位補 0 a << 2 輸出結果 240 ,二進位制解釋: 1111 0000
>> 右移動運算子:把 >> 左邊的運算數的各二進位全部右移若干位, >> 右邊的數指定移動的位數 a >> 2 輸出結果 15 ,二進位制解釋: 0000 1111

邏輯運算子

Python 語言支援邏輯運算子,以下假設變數 a 為 10 ,b為 20 :

運算子 邏輯表示式 描述 例項
and x and y 布林"與" - 如果 x 為 False,x and y 返回 x 的值,否則返回 y 的計算值。 (a and b) 返回 20
or x or y 布林"或" - 如果 x 是 True,它返回 x 的值,否則它返回 y 的計算值。 (a or b) 返回 10
not not x 布林"非" - 如果 x 為 True,返回 False 。如果 x 為 False,它返回 True not(a and b) 返回 False

成員運算子

除了以上的一些運算子之外,Python 還支援成員運算子,測試例項中包含了一系列的成員,包括字串,列表或元組。

運算子 描述 例項
in 如果在指定的序列中找到值返回 True ,否則返回 False x 在 y 序列中 , 如果 x 在 y 序列中返回 True
not in 如果在指定的序列中沒有找到值返回 True ,否則返回 False x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True
#!/usr/bin/python3

a = 10
b = 20
list = [1, 2, 3, 4, 5]

if (a in list):
    print("1 - 變數 a 在給定的列表中 list 中")
else:
    print("1 - 變數 a 不在給定的列表中 list 中")   # true

if (b not in list):
    print("2 - 變數 b 不在給定的列表中 list 中")   # true
else:
    print("2 - 變數 b 在給定的列表中 list 中")

# 修改變數 a 的值
a = 2
if (a in list):
    print("3 - 變數 a 在給定的列表中 list 中")   # true
else:
    print("3 - 變數 a 不在給定的列表中 list 中")

身份運算子

身份運算子用於比較兩個物件的儲存單元

運算子 描述 例項
is is 是判斷兩個識別符號是不是引用自一個物件 x is y , 類似 id(x) == id(y) , 如果引用的是同一個物件則返回 True,否則返回 False
is not is not 是判斷兩個識別符號是不是引用自不同物件 x is not y , 類似 id(x) != id(y)。如果引用的不是同一個物件則返回結果 True,否則返回 False

id() 函式用於獲取物件記憶體地址

#!/usr/bin/python3

a = 20
b = 20

if (a is b):
    print("1 - a 和 b 有相同的標識")   # true
else:
    print("1 - a 和 b 沒有相同的標識")

if (id(a) == id(b)):
    print("2 - a 和 b 有相同的標識")   # true
else:
    print("2 - a 和 b 沒有相同的標識")

# 修改變數 b 的值
b = 30
if (a is b):
    print("3 - a 和 b 有相同的標識")
else:
    print("3 - a 和 b 沒有相同的標識")   # true

if (a is not b):
    print("4 - a 和 b 沒有相同的標識")   # true
else:
    print("4 - a 和 b 有相同的標識")

is== 區別:is 用於判斷兩個變數引用物件是否為同一個, == 用於判斷引用變數的值是否相等

運算子優先順序

以下表格列出了從最高到最低優先順序的所有運算子, 相同單元格內的運算子具有相同優先順序。

運算子 描述
(expressions...) , [expressions...] , {key: value...} , {expressions...} 圓括號的表示式
x[index] , x[index:index] , x(arguments...) , x.attribute 讀取,切片,呼叫,屬性引用
await x await 表示式
** 乘方(指數)
+x , -x , ~x 正,負,按位非 NOT
* , @ , / , // , % 乘,矩陣乘,除,整除,取餘
+ , - 加和減
<< , >> 移位
& 按位與 AND
^ 按位異或 XOR
| 按位或 OR
in , not in , is , is not , < , <= , > , >= , != , == 比較運算,包括成員檢測和標識號檢測
not x 邏輯非 NOT
and 邏輯與 AND
or 邏輯或 OR
if -- else 條件表示式
lambda lambda 表示式
:= 賦值表示式

Pyhton3 已不支援 <> 運算子,可以使用 != 代替

條件控制

if 語句

Python 中用 elif 代替了 else if ,所以 if 語句的關鍵字為:if – elif – else

注意:

  1. 每個條件後面要使用冒號 : ,表示接下來是滿足條件後要執行的語句塊
  2. 使用縮排來劃分語句塊,相同縮排數的語句在一起組成一個語句塊

簡單的 if 例項:

#!/usr/bin/python3

var1 = 100
if var1:    # true
    print("1 - if 表示式條件為 true")
    print(var1)

var2 = 0
if var2:    # false
    print("2 - if 表示式條件為 true")
    print(var2)
print("Good bye!")

狗的年齡計算判斷:

#!/usr/bin/python3

age = int(input("請輸入你家狗狗的年齡: "))
print("")
if age <= 0:
    print("你是在逗我吧!")
elif age == 1:
    print("相當於 14 歲的人。")
elif age == 2:
    print("相當於 22 歲的人。")
elif age > 2:
    human = 22 + (age - 2) * 5
    print("對應人類年齡: ", human)

### 退出提示
input("點選 enter 鍵退出")

數字的比較運算:

#!/usr/bin/python3

# 該例項演示了數字猜謎遊戲
number = 7
guess = -1
print("數字猜謎遊戲!")
while guess != number:
    guess = int(input("請輸入你猜的數字:"))

    if guess == number:
        print("恭喜,你猜對了!")
    elif guess < number:
        print("猜的數字小了...")
    elif guess > number:
        print("猜的數字大了...")

if 巢狀

# !/usr/bin/python3

num = int(input("輸入一個數字:"))
if num % 2 == 0:
    if num % 3 == 0:
        print("你輸入的數字可以整除 2 和 3")
    else:
        print("你輸入的數字可以整除 2,但不能整除 3")
else:
    if num % 3 == 0:
        print("你輸入的數字可以整除 3,但不能整除 2")
    else:
        print("你輸入的數字不能整除 2 和 3")

match

Python中的match語句是Python 3.10及以後版本中引入的新特性,用於模式匹配

它允許你根據物件的模式來檢查物件,並執行相應的程式碼塊。

x = 2
match x:
    case 1:
        print(1)
    case 2:
        print(2)
    case _:
        print('other')

迴圈語句

Python 中的迴圈語句有 forwhile

while 迴圈

同樣需要注意冒號和縮排。另外,在 Python 中沒有 do..while 迴圈。

無限迴圈

#!/usr/bin/python3

var = 1
while var == 1:  # 表示式永遠為 true
    num = int(input("輸入一個數字  :"))
    print("你輸入的數字是: ", num)

print("Good bye!")

無限迴圈在伺服器上客戶端的實時請求非常有用。

簡單語句組

類似 if 語句的語法,如果你的 while 迴圈體中只有一條語句,你可以將該語句與 while 寫在同一行中

#!/usr/bin/python

flag = 1

while (flag): print('歡迎訪問菜鳥教程!')

print("Good bye!")

while-else

else的下級程式碼:
沒有透過 break 退出迴圈,迴圈結束後,會執行的程式碼

num = 1
sum = 5
while num < 5:
    sum += num
    if sum == 10:
        break
    num += 1
else:
    print('沒有執行break語句')

for 語句

for 迴圈可以遍歷任何可迭代物件,如一個列表或者一個字串

break 語句用於跳出當前迴圈體

#!/usr/bin/python3

sites = ["Baidu", "Google", "Runoob", "Taobao"]
for site in sites:
    if site == "Runoob":
        print("菜鳥教程!")
        break
    print("迴圈資料 " + site)
else:
    print("沒有迴圈資料!")
print("完成迴圈!")

for-else

同 while-else

for i in range(5):
    if i == 3:
        print("Found 3, breaking the loop")
        # break
    print(i)
else:
    print("Loop completed without breaking")

range() 函式

如果你需要遍歷數字序列,可以使用內建 range() 函式。它會生成數列

# 指定上限,下限預設 0
for i in range(5):  # [0,4]
    print(i)

# 指定上下限
for i in range(5, 9):  # [5,8]
    print(i)
    
# 指定步長    
for i in range(0, 10, 3):  # {0,3,6,9}
    print(i)
  
# 負數
for i in range(-10, -100, -30):  # {-10,-40,-70}
    print(i)

結合 range()len() 函式以遍歷一個序列的索引

a = ['Google', 'Baidu', 'Runoob', 'Taobao', 'QQ']
for i in range(len(a)):
    print(i, a[i])

輸出結果:

0 Google
1 Baidu
2 Runoob
3 Taobao
4 QQ

使用 range() 函式來建立一個列表

print(list(range(5)))   # [0, 1, 2, 3, 4]

break 和 continue 語句及迴圈中的 else 子句

break 語句可以跳出 for 和 while 的迴圈體。如果你從 for 或 while 迴圈中終止,任何對應的迴圈 else 塊將不執行。

continue 語句被用來告訴 Python 跳過當前迴圈塊中的剩餘語句,然後繼續進行下一輪迴圈。

用於查詢質數的迴圈例子:

#!/usr/bin/python3

for n in range(2, 10):
    for x in range(2, n):
        if n % x == 0:
            print(n, '等於', x, '*', n // x)
            break
    else:
        # 迴圈中沒有找到元素
        print(n, ' 是質數')

pass 語句

pass 是空語句,是為了保持程式結構的完整性。

pass 不做任何事情,一般用做佔位語句

以下例項在字母為 o 時,執行 pass 語句塊:

#!/usr/bin/python3

for letter in 'Runoob':
    if letter == 'o':
        pass
        print('執行 pass 塊')
    print('當前字母 :', letter)

print("Good bye!")

輸出結果為:

當前字母 : R
當前字母 : u
當前字母 : n
執行 pass 塊
當前字母 : o
執行 pass 塊
當前字母 : o
當前字母 : b
Good bye!

輸入和輸出

print 預設輸出是換行的,如果要實現不換行需要在變數末尾加上 end=""

#!/usr/bin/python3

x = "a"
y = "b"
# 換行輸出
print(x)
print(y)

print('---------')
# 不換行輸出
print(x, end=" ")
print(y, end=" ")
print()

執行結果為:

a
b
---------
a b

輸出格式美化

Python 兩種輸出值的方式: 表示式語句和 print() 函式。

第三種方式是使用檔案物件的 write() 方法,標準輸出檔案可以用 sys.stdout 引用。

如果你希望輸出的形式更加多樣,可以使用 str.format() 函式來格式化輸出值。

如果你希望將輸出的值轉成字串,可以使用 repr()str() 函式來實現。

  • str() : 函式返回一個使用者易讀的表達形式
  • repr() : 產生一個直譯器易讀的表達形式
s = 'Hello, Runoob'
print(str(s))   # Hello, Runoob

print(repr(s))  # 'Hello, Runoob'

print(str(1 / 7))   # 0.14285714285714285

x = 10 * 3.25
y = 200 * 200
s = 'x 的值為: ' + repr(x) + ',  y 的值為:' + repr(y) + '...'
print(s)    # x 的值為: 32.5,  y 的值為:40000...

#  repr() 函式可以跳脫字元串中的特殊字元
hello = 'hello, runoob\n'
hellos = repr(hello)
print(hellos)   # 'hello, runoob\n'

# repr() 的引數可以是 Python 的任何物件
print(repr((x, y, ('Google', 'Runoob'))))   # (32.5, 40000, ('Google', 'Runoob'))

兩種方式輸出一個平方與立方的表

for x in range(1, 11):
    print(repr(x).rjust(2), repr(x * x).rjust(3), end=' ')
    # 注意前一行 'end' 的使用
    print(repr(x * x * x).rjust(4))

print("==============================")

for x in range(1, 11):
    print('{0:2d} {1:3d} {2:4d}'.format(x, x * x, x * x * x))

字串物件的 rjust() 方法, 它可以將字串靠右, 並在左邊填充空格。

還有類似的方法, 如 ljust()center() 。 這些方法並不會寫任何東西, 它們僅僅返回新的字串。

另一個方法 zfill() , 它會在數字的左邊填充 0 ,如下所示:

z = '12'.zfill(5)
print(z)    # 00012

z = '-3.14'.zfill(7)
print(z)    # -003.14

z = '3.14159265359'.zfill(5)
print(z)    # 3.14159265359

str.format() 的基本使用如下:

print('{}網址: "{}!"'.format('菜鳥教程', 'www.runoob.com'))   # 菜鳥教程網址: "www.runoob.com!"

在括號中的數字用於指向傳入物件在 format() 中的位置,如下所示:

print('{0} 和 {1}'.format('Google', 'Runoob'))   # Google 和 Runoob

print('{1} 和 {0}'.format('Google', 'Runoob'))   # Runoob 和 Google

如果在 format() 中使用了關鍵字引數, 那麼它們的值會指向使用該名字的引數。

print('{name}網址: {site}'.format(name='菜鳥教程', site='www.runoob.com'))
菜鳥教程網址: www.runoob.com

位置及關鍵字引數可以任意的結合:

>>> print('站點列表 {0}, {1}, 和 {other}。'.format('Google', 'Runoob', other='Taobao'))
站點列表 Google, Runoob, 和 Taobao。

!a (使用 ascii() ), !s (使用 str() ) 和 !r (使用 repr() ) 可以用於在格式化某個值之前對其進行轉化

可選項 : 和格式識別符號可以跟著欄位名。 這就允許對值進行更好的格式化

: 後傳入一個整數,可以保證該域至少有這麼多的寬度。 用於美化表格時很有用。

如果你有一個很長的格式化字串,而你不想將它們分開, 那麼在格式化時透過變數名而非位置會是很好的事情。

最簡單的就是傳入一個字典, 然後使用方括號 [] 來訪問鍵值

也可以透過在 table 變數前使用 ** 來實現相同的功能:

import math

print('常量 PI 的值近似為: {}。'.format(math.pi))   # 常量 PI 的值近似為: 3.141592653589793。

# !r 使用 repr()
print('常量 PI 的值近似為: {!r}。'.format(math.pi))     # 常量 PI 的值近似為: 3.141592653589793。

# 可選項 : 和格式識別符號可以跟著欄位名
print('常量 PI 的值近似為 {0:.3f}。'.format(math.pi))   # 常量 PI 的值近似為 3.142。

# 在 : 後傳入一個整數, 可以保證該域至少有這麼多的寬度
table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
for name, number in table.items():
    print('{0:10} ==> {1:10d}'.format(name, number))
"""
Google     ==>          1
Runoob     ==>          2
Taobao     ==>          3
"""

# 傳入一個字典, 然後使用方括號 [] 來訪問鍵值
table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
print('Runoob: {0[Runoob]:d}; Google: {0[Google]:d}; Taobao: {0[Taobao]:d}'.format(table))      # Runoob: 2; Google: 1; Taobao: 3

# 也可以透過在 table 變數前使用 ** 來實現相同的功能
table = {'Google': 1, 'Runoob': 2, 'Taobao': 3}
print('Runoob: {Runoob:d}; Google: {Google:d}; Taobao: {Taobao:d}'.format(**table))     # Runoob: 2; Google: 1; Taobao: 3

老版本的字串格式化

% 運算子也可以實現字串格式化。 它將左邊的引數作為類似 sprintf() 式的格式化字串,而將右邊的代入,然後返回格式化後的字串

import math

print('常量 PI 的值近似為:%5.3f。' % math.pi)   # 常量 PI 的值近似為:3.142。

因為 str.format() 是比較新的函式, 大多數的 Python 程式碼仍然使用 % 運算子。但是因為這種舊式的格式化最終會從該語言中移除, 應該更多的使用 str.format()

讀取鍵盤輸入

Python 提供了 input() 內建函式 從標準輸入讀入一行文字,預設的標準輸入是鍵盤。

#!/usr/bin/python3

str = input("請輸入:")
print("你輸入的內容是: ", str)

名稱空間和作用域

名稱空間

名稱空間(Namespace) 是從名稱到物件的對映,大部分的名稱空間都是透過 Python 字典來實現的。

名稱空間提供了在專案中避免名字衝突的一種方法。各個名稱空間是獨立的,沒有任何關係的,所以一個名稱空間中不能有重名,但不同的名稱空間是可以重名而沒有任何影響。

一般有三種名稱空間:

  • 內建名稱(built-in names), Python 語言內建的名稱,比如函式名 abs、char 和異常名稱 BaseException、Exception 等等。
  • 全域性名稱(global names),模組中定義的名稱,記錄了模組的變數,包括函式、類、其它匯入的模組、模組級的變數和常量。
  • 區域性名稱(local names),函式中定義的名稱,記錄了函式的變數,包括函式的引數和區域性定義的變數。(類中定義的也是)

img

名稱空間查詢順序:

假設我們要使用變數 runoob ,則 Python 的查詢順序為:區域性的名稱空間 -> 全域性名稱空間 -> 內建名稱空間

如果找不到變數 runoob ,它將放棄查詢並引發一個 NameError 異常

名稱空間的生命週期:

名稱空間的生命週期取決於物件的作用域,如果物件執行完成,則該名稱空間的生命週期就結束。

因此,我們無法從外部名稱空間訪問內部名稱空間的物件。

# var1 是全域性名稱
var1 = 5


def some_func():
    # var2 是區域性名稱
    var2 = 6

    def some_inner_func():
        # var3 是內嵌的區域性名稱
        var3 = 7

作用域

作用域就是一個 Python 程式可以直接訪問名稱空間的正文區域。

在一個 python 程式中,直接訪問一個變數,會從內到外依次訪問所有的作用域直到找到,否則會報未定義的錯誤。

Python 中,程式的變數並不是在哪個位置都可以訪問的,訪問許可權決定於這個變數是在哪裡賦值的。

變數的作用域決定了在哪一部分程式可以訪問哪個特定的變數名稱。Python 的作用域一共有4種,分別是:

有四種作用域:

  • L(Local):最內層,包含區域性變數,比如一個函式/方法內部。
  • E(Enclosing):包含了非區域性(non-local) 也非全域性(non-global) 的變數。比如兩個巢狀函式,一個函式(或類) A 裡面又包含了一個函式 B ,那麼對於 B 中的名稱來說 A 中的作用域就為 nonlocal
  • G(Global):當前指令碼的最外層,比如當前模組的全域性變數。
  • B(Built-in): 包含了內建的變數/關鍵字等,最後被搜尋。

規則順序: L –> E –> G –> B

在區域性找不到,便會去區域性外的區域性找(例如閉包),再找不到就會去全域性找,再者去內建中找。

img

g_count = 0  # 全域性作用域
def outer():
    o_count = 1  # 閉包函式外的函式中
    def inner():
        i_count = 2  # 區域性作用域

內建作用域是透過一個名為 builtin 的標準模組來實現的,但是這個變數名自身並沒有放入內建作用域內,所以必須匯入這個檔案才能夠使用它。在 Python3.0 中,可以使用以下的程式碼來檢視到底預定義了哪些變數:

>>> import builtins
>>> dir(builtins)

Python 中只有模組(module),類(class)以及函式(def、lambda)才會引入新的作用域,其它的程式碼塊(如 if/elif/else/、try/except、for/while等)是不會引入新的作用域的,也就是說這些語句內定義的變數,外部也可以訪問

>>> if True:
...  msg = 'I am from Runoob'
... 
>>> msg
'I am from Runoob'

例項中 msg 變數定義在 if 語句塊中,但外部還是可以訪問的。

如果將 msg 定義在函式中,則它就是區域性變數,外部不能訪問

全域性變數和區域性變數

定義在函式內部的變數擁有一個區域性作用域,定義在函式外的擁有全域性作用域。

區域性變數只能在其被宣告的函式內部訪問,而全域性變數可以在整個程式範圍內訪問。呼叫函式時,所有在函式內宣告的變數名稱都將被加入到作用域中

#!/usr/bin/python3

total = 0  # 這是一個全域性變數


# 可寫函式說明
def sum(arg1, arg2):
    # 返回2個引數的和."
    total = arg1 + arg2  # total在這裡是區域性變數.
    print("函式內是區域性變數 : ", total)  # 30
    return total


# 呼叫sum函式
sum(10, 20)
print("函式外是全域性變數 : ", total)  # 0

global 和 nonlocal 關鍵字

當內部作用域想修改外部作用域的變數時,就要用到 globalnonlocal 關鍵字了。

#!/usr/bin/python3
 
num = 1
def fun1():
    global num  # 需要使用 global 關鍵字宣告
    print(num) 
    num = 123
    print(num)
fun1()
print(num)

輸出結果:

1
123
123

如果要修改巢狀作用域(enclosing 作用域,外層非全域性作用域)中的變數則需要 nonlocal 關鍵字了

#!/usr/bin/python3
 
def outer():
    num = 10
    def inner():
        nonlocal num   # nonlocal關鍵字宣告
        num = 100
        print(num)
    inner()
    print(num)
outer()

輸出結果:

100
100

有一種特殊情況:

#!/usr/bin/python3

a = 10


def test():
    a = a + 1
    print(a)


test()

以上程式執行,報錯資訊如下:

Traceback (most recent call last):
  File "test.py", line 7, in <module>
    test()
  File "test.py", line 5, in test
    a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment

錯誤資訊為區域性作用域引用錯誤,因為 test 函式中的 a 使用的是區域性,未定義,無法修改。

相關文章