本篇是 Python 系列教程第 9 篇,更多內容敬請訪問我的 Python 合集
1 定義函式
在 Python 中,你可以使用 def
關鍵字來定義一個函式。函式定義的基本語法如下:
def function_name(parameters):
# 函式體
# ...
return value
function_name
: 函式的名稱。parameters
: 函式接受的引數列表。引數是可選的。return
: 可選的關鍵字,用於返回函式的結果。如果沒有顯式返回值,預設返回None
。
1.1 示例:定義一個簡單的函式
下面是一個簡單的函式示例,該函式接收兩個引數並返回它們的和:
def add_numbers(a, b):
result = a + b
return result
# 呼叫函式
sum = add_numbers(5, 3)
print(sum) # 輸出 8
1.2 示例:使用遞迴函式
遞迴函式是在函式內部呼叫自身的函式。下面是一個計算階乘的遞迴函式示例:
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1)
result = factorial(5)
print(result) # 輸出 120
2 引數
函式可以接受不同型別的引數,包括位置引數、預設引數、關鍵字引數和可變引數。
2.1 位置引數
位置引數是根據引數在函式呼叫中的位置來確定的。
def greet(name):
print("Hello, " + name)
greet("Alice") # 輸出 "Hello, Alice"
2.2 預設引數
預設引數允許你在定義函式時為引數設定預設值。
def greet(name, greeting="Hello"):
print(greeting + ", " + name)
greet("Alice") # 輸出 "Hello, Alice"
greet("Bob", "Hi") # 輸出 "Hi, Bob"
2.3 關鍵字引數
關鍵字引數允許你透過引數名稱來傳遞值,這使得函式呼叫更加清晰。
def describe_person(name, age, occupation):
print(f"{name} is {age} years old and works as a {occupation}.")
describe_person(name="Alice", age=30, occupation="Engineer")
2.4 可變引數
可變引數允許你在不知道確切引數數量的情況下定義函式。
- 使用星號 (
*args
): 接收任意數量的位置引數。 - 使用雙星號 (
**kwargs
): 接收任意數量的關鍵字引數。
def concatenate_strings(*args):
result = ""
for arg in args:
result += arg
return result
concatenated = concatenate_strings("Hello", " ", "world!")
print(concatenated) # 輸出 "Hello world!"
def describe_person(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
describe_person(name="Alice", age=30, occupation="Engineer")
3 作用域
在 Python 中,函式作用域是指在函式內部定義的變數的作用範圍。作用域規定了變數的可見性和生命週期。理解作用域對於編寫清晰和高效的程式碼非常重要。下面是一些關於 Python 中作用域的基本概念:
3.1 區域性作用域 (Local Scope)
區域性作用域指的是在函式內部定義的變數的作用範圍。這些變數僅在函式內部可用,並且在函式執行完畢後就會被銷燬。
示例:
def my_function():
x = 10 # x 是區域性變數
print(x) # 輸出 10
my_function()
# print(x) # 如果在這裡嘗試訪問 x,將會丟擲 NameError,因為 x 是區域性變數
3.2 全域性作用域 (Global Scope)
全域性作用域是指在整個程式範圍內定義的變數的作用範圍。這些變數可以在程式的任何地方訪問,除非它們被區域性作用域中的同名變數所遮蔽。
示例:
x = 5 # x 是全域性變數
def my_function():
print(x) # 訪問全域性變數 x
my_function()
print(x) # 輸出 5
3.3 內嵌作用域 (Enclosing Scope)
當一個函式內部定義了另一個函式時,內部函式可以訪問外部函式的區域性變數,這種情況稱為內嵌作用域。
示例:
def outer_function():
x = 30 # x 是 outer_function 的區域性變數
def inner_function():
print(x) # 訪問外部函式的區域性變數 x
inner_function()
outer_function()
3.4 內建作用域 (Built-in Scope)
Python 自帶了一些預定義的全域性變數和函式,例如 len()
、print()
等。這些都位於內建作用域中,可以在程式的任何地方訪問。
3.5 LEGB 規則
LEGB 是一個縮寫詞,代表 Local、Enclosing、Global 和 Built-in,這是 Python 中查詢變數的作用域順序:
- Local: 在當前函式的作用域中查詢變數。
- Enclosing: 如果在當前函式中找不到變數,則向上一級函式的作用域中查詢。
- Global: 如果在所有內嵌作用域中都找不到變數,則在全域性作用域中查詢。
- Built-in: 最後,在內建作用域中查詢。
3.6 nonlocal
和 global
關鍵字
nonlocal
和 global
關鍵字用於宣告變數的作用域。
nonlocal
: 用於宣告變數屬於最近一個擁有該變數的內嵌作用域。從字面意思“非本地”就能理解並不是本層的。global
: 用於宣告一個變數屬於全域性作用域。
示例:
x = 50 # 全域性變數
y = 50 # 全域性變數
def outer_function():
x = 100 # outer_function 的區域性變數
y = 100 # outer_function 的區域性變數
def inner_function():
nonlocal x # 宣告 x 是 outer_function 的區域性變數
x = 200 # 修改 outer_function 的區域性變數 x
print("Inner x:", x) # 輸出 200
global y # 宣告 y 是 全域性變數
print("Inner y:", y) # 輸出 50
inner_function()
# 訪問 outer_function 的區域性變數 x
print("Outer x:", x) # 輸出 200
outer_function()
print("Global x:", x) # 輸出 50
print("Global y:", y) # 輸出 50
在這個例子中,inner_function
修改了 outer_function
中的 x
,而不是建立一個新的區域性變數。inner_function
修改了全域性的y
,而不是 outer_function
中的 y
3.7 總結
- 區域性變數只在其定義的函式內部可見。
- 全域性變數在整個程式中可見。
- 內嵌作用域允許內部函式訪問外部函式的區域性變數。
- 內建作用域包含了 Python 的預定義內建函式和變數。
- 內部函式修改外部函式的變數要先用
nonlocal
先宣告;內部函式修改全域性變數要先用global
宣告。
4 常用內建函式
那可太多了,剛好湊字數(不是)
Python 提供了許多內建函式,這些函式可以幫助你執行各種常見的任務,而無需編寫額外的程式碼。下面是一些常用的內建函式及其說明:
4.1 資料型別轉換函式
這些函式用於將一種資料型別轉換為另一種資料型別。
int()
: 將給定的值轉換為整數。
int("42") # 結果是 42
float()
: 將給定的值轉換為浮點數。
float("3.14") # 結果是 3.14
str()
: 將給定的值轉換為字串。
str(100) # 結果是 "100"
bool()
: 將給定的值轉換為布林值。
bool(1) # 結果是 True
list()
: 將給定的值轉換為列表。
list("hello") # 結果是 ['h', 'e', 'l', 'l', 'o']
tuple()
: 將給定的值轉換為元組。
tuple("hello") # 結果是 ('h', 'e', 'l', 'l', 'o')
set()
: 將給定的值轉換為集合。
set("hello") # 結果是 {'h', 'e', 'l', 'o'}
dict()
: 將給定的鍵值對轉換為字典。
dict([(1, "one"), (2, "two")]) # 結果是 {1: "one", 2: "two"}
4.2 控制流相關的函式
這些函式用於控制程式的執行流程。
abs()
: 返回數值的絕對值。
abs(-5) # 結果是 5
all()
: 如果可迭代物件(說白了就是陣列)的所有元素都為True
,則返回True
;否則返回False
。
all([True, True, True]) # 結果是 True
any()
: 如果可迭代物件中至少有一個元素為True
,則返回True
;否則返回False
。
any([False, True, False]) # 結果是 True
enumerate()
: 返回一個列舉物件,可以同時獲取索引和值。適用場景:處理列表、元組或字串中的元素時,需要同時訪問索引和值。
for index, char in enumerate("hello"):
print(index, char)
# 輸出:
# 0 h
# 1 e
# 2 l
# 3 l
# 4 o
fruits = ["apple", "banana", "cherry", "date"]
for index, fruit in enumerate(fruits):
print(f"Index: {index}, Fruit: {fruit}")
# 輸出
# 0 apple
# 1 banana
# 2 cherry
# 3 date
sorted()
: 對可迭代物件進行排序。
sorted([3, 1, 2]) # 結果是 [1, 2, 3]
reversed()
: 返回一個反轉的迭代器。注意不能直接列印,需要遍歷。
print(reversed([1, 2, 3]))
# 直接列印的花會輸出 <list_reverseiterator object at 0x000001526CE4AAA0>
for x in reversed([1, 2, 3]):
print(x)
# 輸出
# 3
# 2
# 1
zip()
: 將多個可迭代物件打包成一個元組的列表。
for x in zip([1, 2, 3], ['a', 'b', 'c']):
print(x)
# 輸出
# (1, 'a')
# (2, 'b')
# (3, 'c')
4.3 數學相關的函式
這些函式用於執行基本的數學運算。
round()
: 四捨五入。
round(3.14) # 結果是 3
min()
: 返回可迭代物件中的最小值。
min([1, 2, 3]) # 結果是 1
max()
: 返回可迭代物件中的最大值。
max([1, 2, 3]) # 結果是 3
sum()
: 返回可迭代物件中的元素之和。
sum([1, 2, 3]) # 結果是 6
4.4 字串相關的函式
這些函式用於處理字串。
len()
: 返回物件的長度。
len("hello") # 結果是 5
str.join()
: 使用指定的分隔符連線字串列表。
"-".join(["a", "b", "c"]) # 結果是 "a-b-c"
print()
: 列印輸出。
print("Hello, world!") # 輸出 "Hello, world!"
4.5 其他常用函式
type()
: 返回物件的型別。
type(10) # 結果是 <class 'int'>
id()
: 返回物件的識別符號。
id(10) # 返回物件的唯一識別符號
input()
: 從標準輸入讀取一行。
name = input("Enter your name: ")
help()
: 顯示幫助文件。
help(len) # 顯示 len 函式的幫助文件
dir()
: 列出物件的所有屬性和方法。
dir("hello") # 列出字串物件的方法和屬性
eval()
: 評估一個字串,並執行其中的 Python 表示式。
eval("1 + 2") # 結果是 3
exec()
: 動態執行 Python 程式碼。
exec("print('Hello, world!')") # 輸出 "Hello, world!"
globals()
: 返回一個字典,其中包含了當前模組的全域性變數及其值。
# 定義全域性變數
x = 10
print(globals())
# 輸出,可以在末尾看到變數x
# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000017E8933BCB0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:\\PycharmProjects\\demo1\\Hello.py', '__cached__': None, 'x': 10}
globals()
函式主要用於以下幾種情況:
- 動態訪問全域性變數:
# 定義全域性變數 x = 10 y = 20 # 使用 globals() 訪問全域性變數 def access_globals(): global_var_x = globals()["x"] global_var_y = globals()["y"] print(global_var_x) # 輸出 10 print(global_var_y) # 輸出 20 access_globals()
- 檢查全域性名稱空間的內容:
# 定義全域性變數 x = 10 y = 20 # 檢查全域性名稱空間的內容 def inspect_globals(): global_vars = globals() for key, value in global_vars.items(): print(key, ":", value) inspect_globals() # 輸出 # __name__ : __main__ # __doc__ : None # __package__ : None # __loader__ : <_frozen_importlib_external.SourceFileLoader object at 0x000001EA9BCEBCB0> # __spec__ : None # __annotations__ : {} # __builtins__ : <module 'builtins' (built-in)> # __file__ : D:\PycharmProjects\demo1\Hello.py # __cached__ : None # x : 10 # y : 20 # inspect_globals : <function inspect_globals at 0x000001EA9BE684A0>
- 動態建立變數:
def create_variable(var_name, var_value): # 動態建立全域性變數 globals()[var_name] = var_value create_variable("z", 30) print(z) # 輸出 30
- 除錯和開發:
-
在除錯或開發過程中,
globals()
可以幫助你瞭解當前模組的狀態。 -
locals()
: 返回一個字典,其中包含了當前模組的區域性變數及其值。作用和上面globals()
函式類似。
locals() # 返回區域性變數的字典
callable()
: 檢查一個物件是否可呼叫。
callable(print) # 結果是 True
isinstance()
: 檢查一個物件是否為指定類的例項。
isinstance(10, int) # 結果是 True
getattr()
: 獲取物件的屬性。
getattr("hello", "__len__")() # 結果是 5,注意後面的()不能省
hasattr()
: 檢查物件是否有指定的屬性。
hasattr("hello", "__len__") # 結果是 True
setattr()
: 設定物件的屬性。
class MyClass:
pass
obj = MyClass()
setattr(obj, "value", 10)
print(obj.value) # 輸出 10
delattr()
: 刪除物件的屬性。
delattr(obj, "value")
map()
: 允許你對序列中的每個元素應用一個函式,並返回一個新的序列。
map(function, iterable, ...)
# function: 一個函式,將應用於每個元素。
# iterable: 一個或多個可迭代物件(如列表、元組等),其中的每個元素都將被傳遞給 function。
map()
函式返回一個 map
物件,這個物件是一個迭代器,你可以透過 list()
、tuple()
或者遍歷來獲取結果。關於迭代器(iterator)和可迭代物件(iterable)的區別和關係請移步文末。
-
list()
: 返回列表,用途包括: -
建立空列表。
-
將迭代器或任何型別可迭代物件轉為列表。
-
複製列表。
函式有太多了,這裡就不一一列舉了。
5 lambda表示式
在 Python 中,lambda 表示式是一種建立小型匿名函式的方式。它允許你在一行程式碼內快速定義簡單的函式,而無需使用標準的 def 關鍵字來定義函式。
5.1 語法
lambda arguments: expression
lambda
是用來宣告表示式的關鍵詞。arguments
一個或多個引數,它們之間用逗號 , 分隔。expression
一個有效的 Python 表示式,該表示式將被計算並作為 lambda 函式的結果返回。
5.2 注意事項
lambda
表示式通常用於簡單的操作,如果邏輯較為複雜,建議使用傳統的def
關鍵字定義函式。lambda
函式只能包含一個表示式,不能包含多行程式碼。
5.3 使用示例
讓我們來看幾個 lambda
表示式的例子:
5.3.1 簡單的 lambda 函式
# 定義一個 lambda 函式,用於計算兩個數的和
add = lambda x, y: x + y
# 呼叫 lambda 函式
result = add(5, 3)
print(result) # 輸出: 8
5.3.2 使用 lambda 函式進行排序
假設我們有一個包含字典的列表,並且我們想按照字典中的某個鍵來進行排序:
people = [
{'name': 'Alice', 'age': 25},
{'name': 'Bob', 'age': 22},
{'name': 'Charlie', 'age': 30}
]
# 使用 lambda 函式作為 key 引數對列表進行排序
sorted_people = sorted(people, key=lambda person: person['age'])
# 列印排序後的列表
for person in sorted_people:
print(person)
# 輸出結果將根據age進行排序:
# {'name': 'Bob', 'age': 22}
# {'name': 'Alice', 'age': 25}
# {'name': 'Charlie', 'age': 30}
5.3.3 在高階函式中使用 lambda
Python 中的 map()
, filter()
, reduce()
等函式都可以接受 lambda
函式作為引數。
- 使用
map()
函式(上面已經介紹map()
函式的功能):
numbers = [1, 2, 3, 4, 5]
squares = map(lambda x: x**2, numbers)
print(list(squares)) # 輸出: [1, 4, 9, 16, 25]
- 使用
filter()
函式(功能是過濾值):
numbers = [1, 2, 3, 4, 5]
even_numbers = filter(lambda x: x % 2 == 0, numbers)
print(list(even_numbers)) # 輸出: [2, 4]
- 使用
reduce()
函式(功能是做累積)需要匯入functools
模組:
from functools import reduce
numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)
print(product) # 輸出: 120
擴充:
迭代器(iterator)和可迭代物件(iterable) 是兩個緊密相關的概念,它們都能實現迴圈遍歷。通常透過呼叫可迭代物件的 __iter__
方法來建立迭代器。
下面是一個簡單的例子,演示如何使用可迭代物件和迭代器:
# 定義一個可迭代物件(列表)
my_list = [1, 2, 3, 4, 5]
# 獲取該可迭代物件的迭代器,兩種方式均可
# iterator = iter(my_list)
iterator = my_list.__iter__()
# 使用迭代器遍歷列表
while True:
try:
item = next(iterator)
print(item)
except StopIteration:
break
Q: 可迭代物件有哪些?
A: 很多,列表(List)、元組(Tuple)、字典(Dictionary)、集合(Set)、甚至字串(String)、範圍(Range)都是。
Q: 如何建立迭代器?
A: 使用 iter() 和 next() 方法。