Python函式

救苦救难韩天尊發表於2024-08-28

本篇是 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 中查詢變數的作用域順序:

  1. Local: 在當前函式的作用域中查詢變數。
  2. Enclosing: 如果在當前函式中找不到變數,則向上一級函式的作用域中查詢。
  3. Global: 如果在所有內嵌作用域中都找不到變數,則在全域性作用域中查詢。
  4. Built-in: 最後,在內建作用域中查詢。

3.6 nonlocalglobal 關鍵字

nonlocalglobal 關鍵字用於宣告變數的作用域。

  • 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() 函式主要用於以下幾種情況:

  1. 動態訪問全域性變數
# 定義全域性變數 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()
  1. 檢查全域性名稱空間的內容
# 定義全域性變數 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>
  1. 動態建立變數
def create_variable(var_name, var_value):    # 動態建立全域性變數    globals()[var_name] = var_value create_variable("z", 30) print(z)  # 輸出 30
  1. 除錯和開發
  • 在除錯或開發過程中,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() 方法。

相關文章