目錄
- 1. 命名空間與作用域
- 1.1 命名空間概述
- 1.2 作用域
- 1.2.1 局部作用域
- 1.2.2 全局作用域
- 1.2.3 修改全局變量
- 1.2.4 嵌套作用域
- 2. 繼承
- 3. 多態(Polymorphism)
1. 命名空間與作用域
1.1 命名空間概述
命名空間是一個從名字到對象的映射,它在Python程序中定義了一系列變量的名稱。每個命名空間都是一個字典的實現,雖然字典是直接由用戶創建的,但是命名空間的創建和使用完全由解釋器來控制。
1.2 作用域
在Python編程中,作用域(Scope)是指程序中定義變量的區域,決定了變量的可見性和生命周期。它規定了程序中哪些區域能夠訪問特定的變量名稱。
Python中的作用域主要有四種:
-
內置作用域(Built-in Scope):內置作用域包含了Python內置的函數和異常類,以及內置的函數和異常名(如
abs()
,int()
,list()
,Exception
等)。這個作用域在Python解釋器啟動時創建,每個模塊都可以訪問內置作用域。
然而,在Python中,我們通常不會直接提及“內置作用域”(Built-in Scope)作為一個獨立的作用域級別,盡管技術上內置名稱(如內置函數和異常等)確實存在于一個特定的命名空間中。然而,當我們討論作用域時,我們通常指的是全局作用域、局部作用域和(可能的)嵌套作用域。 -
局部作用域(Local Scope):局部作用域是在函數或方法內部定義的變量的作用域。函數參數和函數內部定義的變量都屬于局部作用域。局部變量在函數調用時創建,在函數返回時銷毀。
-
全局作用域(Global Scope):全局作用域是最外層的命名空間,在模塊級別定義的變量屬于全局作用域。全局作用域在程序執行時創建,程序的所有模塊都可以訪問全局作用域中的變量。
-
嵌套作用域(Enclosing Scope):在嵌套函數中,外部函數定義的變量對內部函數而言是可見的,但僅當內部函數沒有定義同名的局部變量時。這個作用域在嵌套函數或類定義時創建。
在Python中,變量的訪問遵循LEGB規則,即Local(局部作用域)-> Enclosing(嵌套作用域,如果有的話)-> Global(全局作用域)-> Built-in(內置作用域)。這意味著,在查找一個變量時,Python會首先在當前的作用域中查找,如果找不到,它會向上一級作用域查找,直到找到為止或者引發NameError
。
需要注意的是,Python中沒有塊級作用域(Block Scope),也就是說,在if
、for
或while
語句塊中定義的變量,實際上是定義在包含該語句塊的函數或模塊的全局作用域或局部作用域中。這是與其他一些編程語言(如C++或Java)不同的地方。
1.2.1 局部作用域
在Python中,局部作用域通常指的是在函數內部定義的變量所存在的作用范圍。這些變量只能在定義它們的函數內部被訪問。當函數被調用時,這些局部變量被創建,并在函數執行完畢后被銷毀。
為了說明局部作用域在金融領域的應用,我們可以考慮一個簡單的例子:
一個計算復利(Compound Interest)的函數。在這個函數中,我們將使用局部變量來存儲如利率(interest rate)、本金(principal amount)、年份(years)和計算結果(future value)等信息。
def calculate_compound_interest(principal, annual_interest_rate, years):# 這些變量是局部變量,只能在calculate_compound_interest函數內部訪問# 假設一年有365天,這是為了簡化計算(實際中應考慮閏年等情況)days_in_year = 365# 將年利率轉換為日利率daily_interest_rate = annual_interest_rate / (100 * days_in_year)# 使用復利公式計算未來的價值future_value = principal * ((1 + daily_interest_rate) ** (days_in_year * years))# 返回計算結果return future_value# 示例:計算10000元本金在5%年利率下,10年后的復利
principal = 10000
annual_interest_rate = 5
years = 10
result = calculate_compound_interest(principal, annual_interest_rate, years)
print(f"未來的價值是: {result:.2f}元")
在這個示例中,days_in_year
、daily_interest_rate
和future_value
都是局部變量。它們在calculate_compound_interest
函數內部被定義和使用,并且在函數執行完畢后被銷毀。注意,這些變量在函數外部是不可見的(即不能從函數外部直接訪問)。這就是局部作用域的基本原理。
1.2.2 全局作用域
全局作用域是整個Python腳本中都可以訪問的作用域。在這里,我們將定義全局變量total_investment
和total_return
。
示例:假設我們有一個投資組合,我們想要計算其投資回報率(ROI,Return on Investment)。我們可以定義全局變量來存儲投資的總金額和回報金額,然后在函數中計算ROI。
# 全局變量
total_investment = 100000 # 初始投資金額為10萬
total_return = 15000 # 假設回報金額為1萬5def calculate_roi():# 函數內部的計算將在局部作用域中進行roi = (total_return / total_investment) * 100 # 計算ROIprint(f"投資回報率為:{roi}%")# 調用函數,計算并打印ROI
calculate_roi()
在這個例子中,total_investment
和total_return
是全局變量,它們可以在全局作用域中被任何代碼訪問。我們在calculate_roi
函數內部引用了這兩個全局變量來計算ROI。
1.2.3 修改全局變量
如果我們想在函數內部修改全局變量的值,我們需要使用global
關鍵字來聲明。但是,在大多數情況下,最好避免在函數內部修改全局變量,因為這可能導致代碼更難理解和維護。不過,為了完整解釋,我們還是給出一個例子:
# 全局變量
total_investment = 100000 # 初始投資金額為10萬
total_return = 15000 # 假設回報金額為1萬5def update_investment_and_return(new_investment, new_return):global total_investment, total_returntotal_investment = new_investment # 更新投資金額total_return = new_return # 更新回報金額calculate_roi() # 重新計算并打印ROI# 調用函數,更新投資金額和回報金額,并重新計算ROI
update_investment_and_return(120000, 20000)
在這個例子中,我們定義了一個新函數update_investment_and_return
,它接受新的投資金額和回報金額作為參數,并使用global
關鍵字聲明了要修改的全局變量。然后,它更新了這些全局變量的值,并重新計算了ROI。
1.2.4 嵌套作用域
在Python中,嵌套作用域通常與嵌套函數相關,即一個函數內部定義的另一個函數。在這種情況下,內部函數可以訪問其外部函數(即包含它的函數)的局部作用域中的變量,這被稱為封閉作用域或外部作用域。
下面是一個使用嵌套作用域和金融示例的Python代碼。我們將創建一個計算貸款支付金額的函數,并在其中定義一個嵌套的利率計算函數。
def calculate_monthly_payment(principal, annual_rate, term_years):# 將年利率轉換為月利率def calculate_monthly_rate(annual_rate):return annual_rate / 12 / 100# 嵌套函數內部使用外部函數的變量monthly_rate = calculate_monthly_rate(annual_rate)# 貸款期數(月份)total_payments = term_years * 12# 使用公式計算每月支付金額(這里簡化處理,沒有包含復雜的還款計算)# 注意:這里僅用于示例,真實情況中需使用專門的貸款公式monthly_payment = principal * monthly_rate / (1 - (1 + monthly_rate) ** -total_payments)return round(monthly_payment, 2) # 保留兩位小數# 示例:計算50,000元的貸款在5%的年利率下,10年期限的每月支付金額
loan_amount = 50000
annual_interest_rate = 5
loan_term = 10
monthly_payment = calculate_monthly_payment(loan_amount, annual_interest_rate, loan_term)
print(f"每月需要支付: {monthly_payment} 元")
在上面的示例中,calculate_monthly_payment
函數是一個外部函數,它接收貸款本金、年利率和貸款期限(年)作為參數。這個函數內部定義了一個嵌套函數 calculate_monthly_rate
,用于將年利率轉換為月利率。嵌套函數可以訪問其外部函數 calculate_monthly_payment
的作用域中的變量 annual_rate
。然后,外部函數使用嵌套函數計算出的月利率來計算每月的支付金額,并返回結果。
注意,雖然嵌套函數在這里很有用,但它不是必需的。你也可以直接在 calculate_monthly_payment
函數中編寫計算月利率的代碼,而不是使用嵌套函數。但是,當邏輯變得更加復雜或者你需要將一部分邏輯封裝起來以便在多個地方重用時,嵌套函數就會非常有用。
2. 繼承
在Python中,繼承是一種面向對象編程的重要特性,它允許我們創建一個新的類(稱為子類或派生類),這個類繼承自一個或多個已存在的類(稱為父類或基類)。子類可以繼承父類的屬性和方法,并可以添加新的屬性和方法或重寫父類的方法。
在金融領域,繼承可以用于創建不同種類的金融產品類,例如,一個基本的金融產品類可以被繼承以創建具體的股票類、債券類、基金類等。下面是一個使用Python繼承及金融領域的示例。
# 定義一個基本的金融產品類
class FinancialProduct:def __init__(self, name, price):self.name = nameself.price = pricedef buy(self):print(f"購買了 {self.name},價格為 {self.price} 元。")def sell(self):print(f"出售了 {self.name},價格為 {self.price} 元(僅為示例,實際賣出價格可能不同)。")# 繼承自金融產品類的股票類
class Stock(FinancialProduct):def __init__(self, name, price, symbol):super().__init__(name, price) # 調用父類的初始化方法self.symbol = symbol # 股票特有的屬性:股票代碼def dividend(self, amount):print(f"股票 {self.name} (代碼 {self.symbol}) 分紅 {amount} 元。")# 創建一個股票對象并測試其方法
if __name__ == "__main__":apple_stock = Stock("蘋果公司股票", 150.0, "AAPL")apple_stock.buy()apple_stock.sell()apple_stock.dividend(3.0)# 嘗試使用基類的方法創建一個普通的金融產品(不是股票)bond = FinancialProduct("國債", 100.0)bond.buy()bond.sell()
在這個例子中,我們定義了一個FinancialProduct
類作為基類,它包含了金融產品的一些通用屬性和方法,如name
(產品名稱)、price
(產品價格)、buy
(購買)和sell
(出售)。
然后我們定義了一個Stock
類,它繼承自FinancialProduct
類。Stock
類添加了一個額外的屬性symbol
(股票代碼)和一個新的方法dividend
(分紅)。Stock
類的__init__
方法調用了父類FinancialProduct
的__init__
方法以設置通用的屬性和方法,然后添加了Stock
特有的屬性。
在__main__
部分,我們創建了一個Stock
對象和一個FinancialProduct
對象,并分別調用了它們的方法。這展示了子類如何使用繼承來重用父類的代碼,并添加自己的特定屬性和方法。
3. 多態(Polymorphism)
多態是面向對象編程的三大特性之一(繼承、封裝和多態),它意味著不同的對象對同一消息做出不同的響應。在Python中,多態性主要通過方法重寫(Overriding)和方法重載(Overloading,雖然Python本身不支持傳統的函數重載)來實現。
但是,在Python中,我們通常通過定義接口(通過抽象基類實現)或使用鴨子類型(duck typing)來實現多態性。
抽象基類允許你定義接口,子類可以繼承這些接口并實現所需的方法。而鴨子類型則是一種動態類型方式,它并不關心對象的類型,只關注對象是否擁有某些方法或屬性。
下面是一個使用Python的抽象基類和鴨子類型來展示金融領域多態性的示例:
首先,我們定義一個抽象基類FinancialProduct,它定義了一個計算回報率的接口:
from abc import ABC, abstractmethodclass FinancialProduct(ABC):@abstractmethoddef calculate_return(self):pass
接著,我們定義兩個具體的金融產品類Stock和Bond,它們繼承自FinancialProduct并實現了calculate_return方法:
class Stock(FinancialProduct):def __init__(self, name, current_price, purchase_price):self.name = nameself.current_price = current_priceself.purchase_price = purchase_pricedef calculate_return(self):return (self.current_price - self.purchase_price) / self.purchase_priceclass Bond(FinancialProduct):def __init__(self, name, face_value, coupon_rate, years_to_maturity):self.name = nameself.face_value = face_valueself.coupon_rate = coupon_rate / 100 # 將百分比轉換為小數self.years_to_maturity = years_to_maturitydef calculate_return(self):# 這里為了簡化,我們假設每年回報率是固定的return self.coupon_rate
現在我們可以定義一個函數來處理這些金融產品,這個函數不關心產品的具體類型,只要它實現了calculate_return方法即可:
def show_return(product):print(f"產品 {product.name} 的回報率為: {product.calculate_return() * 100:.2f}%")# 創建金融產品實例
stock = Stock("蘋果公司股票", 150.0, 100.0)
bond = Bond("五年期國債", 1000.0, 5.0, 5)# 調用函數,展示回報率
show_return(stock)
show_return(bond)
在這個例子中,show_return函數展示了多態性。它接受一個FinancialProduct類型的參數,但實際上可以接受任何實現了calculate_return方法的對象。這就是鴨子類型的體現:如果它走起路來像鴨子(即擁有calculate_return方法),那么我們就可以把它當作鴨子來處理。