完整代碼如下:?
class BankAccount:def __init__(self, account_holder, initial_balance=0):"""初始化銀行賬戶:param account_holder: 賬戶持有人姓名:param initial_balance: 初始余額,默認為0"""self.account_holder = account_holderself.balance = initial_balanceself.transactions = [] # 記錄交易歷史def deposit(self, amount):"""存款操作:param amount: 存款金額""" if amount <= 0:print("存款金額必須大于0")returnself.balance += amountself.transactions.append(f"存款: +{amount:.2f}")print(f"成功存款 {amount:.2f}。當前余額: {self.balance:.2f}")def withdraw(self, amount):"""取款操作:param amount: 取款金額"""if amount <= 0:print("取款金額必須大于0")returnif amount > self.balance:print("余額不足,無法完成取款")returnself.balance -= amountself.transactions.append(f"取款: -{amount:.2f}")print(f"成功取款 {amount:.2f}。當前余額: {self.balance:.2f}")def get_balance(self):"""獲取當前余額"""return self.balancedef get_transaction_history(self):"""獲取交易歷史記錄"""return self.transactionsdef __str__(self):return f"賬戶持有人: {self.account_holder}, 當前余額: {self.balance:.2f}"if __name__ == "__main__":name = input("請輸入賬戶持有人姓名: ")while True:try:initial_deposit = float(input("請輸入初始存款金額: "))if initial_deposit < 0:print("初始存款金額不能為負數,請重新輸入")continuebreakexcept ValueError:print("請輸入有效的數字")# 創建賬戶account = BankAccount(name, initial_deposit)print(f"\n賬戶創建成功!")print(account)# 循環操作while True:print("\n請選擇操作:")print("1. 存款")print("2. 取款")print("3. 查詢余額")print("4. 查看交易記錄")print("5. 退出") choice = input("請輸入選項(1-5): ")if choice == "1":# 存款while True:try:amount = float(input("請輸入存款金額: "))if amount <= 0:print("存款金額必須大于0")continueaccount.deposit(amount)breakexcept ValueError:print("請輸入有效的數字")elif choice == "2":# 取款while True:try:amount = float(input("請輸入取款金額: "))if amount <= 0:print("取款金額必須大于0")continueaccount.withdraw(amount)breakexcept ValueError:print("請輸入有效的數字")elif choice == "3":# 查詢余額print(f"\n當前余額: {account.get_balance():.2f}")elif choice == "4":# 查看交易記錄print("\n交易記錄:") for transaction in account.get_transaction_history():print(transaction)if not account.get_transaction_history():print("暫無交易記錄")elif choice == "5":# 退出print("感謝使用銀行賬戶系統,再見!")breakelse:print("無效的選項,請重新輸入")
一、系統框架
-
類結構:
- 核心類?
BankAccount
?封裝了銀行賬戶的所有功能 - 使用面向對象編程(OOP)思想,將數據和操作封裝在一起
- 核心類?
-
主要組件:
class BankAccount:# 1. 初始化方法def __init__(self, account_holder, initial_balance=0)# 2. 存款功能def deposit(self, amount)# 3. 取款功能 def withdraw(self, amount)# 4. 查詢功能def get_balance(self)def get_transaction_history(self)# 5. 字符串表示def __str__(self)
-
用戶交互:
- 主程序通過?
if __name__ == "__main__":
?實現交互式命令行界面 - 使用 while 循環保持程序持續運行
- 主程序通過?
二、設計思路
-
數據建模:
- 賬戶屬性:持有人姓名、余額、交易記錄
- 交易記錄使用列表存儲,記錄每次操作的詳細信息
-
功能實現原則:
- 單一職責原則:每個方法只做一件事
- 輸入驗證:對所有用戶輸入進行有效性檢查
- 事務記錄:自動記錄每筆交易的詳細信息
- 防錯設計:處理負數金額、余額不足等異常情況
-
交互流程:
開始 → 輸入賬戶信息 → 主菜單 → 選擇操作 → 執行功能 → 返回主菜單 → 退出
-
異常處理:
- 使用 try-except 處理非數字輸入
- 使用條件判斷處理業務邏輯錯誤(如余額不足)
三、關鍵設計點
-
狀態管理:
balance
?變量實時跟蹤賬戶余額transactions
?列表完整記錄所有交易歷史
-
用戶友好性:
- 清晰的提示信息
- 格式化的金額顯示(保留兩位小數)
- 操作結果的即時反饋
-
擴展性考慮:
- 通過類的方式實現,便于后續添加新功能
- 交易記錄采用標準格式,便于擴展分析功能
四、典型工作流程示例
- 用戶輸入姓名和初始金額
- 系統創建賬戶對象
- 用戶選擇存款:
- 輸入存款金額
- 系統驗證并執行存款
- 更新余額和交易記錄
- 用戶選擇查詢:
- 系統顯示當前余額
- 用戶退出系統
五、代碼分析
整體結構分析
該代碼定義了一個BankAccount
類來模擬銀行賬戶的基本操作,包括初始化賬戶、存款、取款、查詢余額、查看交易記錄等功能。在if __name__ == "__main__"
模塊中,實現了與用戶的交互,讓用戶能夠創建賬戶并進行各種操作。
類定義分析
__init__
方法
- 功能:初始化銀行賬戶對象。
- 接受
account_holder
(賬戶持有人姓名)和initial_balance
(初始余額,默認為0)兩個參數。 - 初始化了三個實例變量:
self.account_holder
(存儲賬戶持有人姓名)、self.balance
(存儲賬戶余額)、self.transactions
(存儲交易歷史記錄的空列表)。
- 接受
- 優點:通過參數初始化實例變量,使每個賬戶對象在創建時就有明確的初始狀態。
deposit
方法
- 功能:實現存款操作。
- 檢查存款金額
amount
是否小于等于0,若為真,打印提示信息并返回,不進行存款操作。 - 否則,將存款金額加到賬戶余額
self.balance
上,并將存款交易記錄(格式為"存款: +{amount:.2f}"
)添加到self.transactions
列表中,同時打印存款成功信息和當前余額。
- 檢查存款金額
- 優點:有輸入校驗(金額有效性檢查),保證了存款操作的合理性,并且及時更新賬戶余額和記錄交易歷史。
withdraw
方法
- 功能:實現取款操作。
- 先檢查取款金額
amount
是否小于等于0,若是,打印提示信息并返回。 - 再檢查取款金額是否大于當前賬戶余額
self.balance
,若大于,打印余額不足提示信息并返回。 - 否則,從賬戶余額中減去取款金額,并將取款交易記錄(格式為
"取款: -{amount:.2f}"
)添加到self.transactions
列表中,同時打印取款成功信息和當前余額。
- 先檢查取款金額
- 優點:具備完善的輸入校驗(金額有效性和余額充足性檢查),確保取款操作符合實際業務邏輯,保護賬戶資金安全。
get_balance
方法
- 功能:簡單返回當前賬戶的余額
self.balance
。 - 優點:提供了一種便捷的方式獲取賬戶余額,符合面向對象編程中封裝的思想(外部通過方法訪問內部數據)。
get_transaction_history
方法
- 功能:返回存儲交易歷史記錄的
self.transactions
列表。 - 優點:方便用戶查看賬戶的交易明細,是對賬戶操作歷史的記錄和展示。
__str__
方法
- 功能:定義了對象的字符串表示形式。當使用
print()
函數打印賬戶對象時,會自動調用該方法,返回一個包含賬戶持有人姓名和當前余額的字符串(格式為"賬戶持有人: {self.account_holder}, 當前余額: {self.balance:.2f}"
)。 - 優點:使賬戶對象在打印時能以友好、易讀的方式呈現信息,方便用戶直觀了解賬戶基本情況,也有利于調試和日志記錄等場景。
if __name__ == "__main__"
模塊分析
- 獲取用戶輸入并創建賬戶:
- 使用
input()
函數獲取用戶輸入的賬戶持有人姓名name
。 - 通過循環和
try-except
塊,確保用戶輸入的初始存款金額initial_deposit
是有效的數字且不為負數,然后創建BankAccount
對象account
。 - 打印賬戶創建成功信息和賬戶對象(調用
__str__
方法)。
- 使用
- 用戶操作循環:
- 進入一個無限循環,展示操作菜單(存款、取款、查詢余額、查看交易記錄、退出)。
- 根據用戶輸入的選項
choice
,執行相應的操作(調用BankAccount
類的對應方法)。 - 對于每個操作(如存款、取款),同樣使用循環和
try-except
塊確保用戶輸入的金額是有效的數字,并進行相應的業務邏輯處理(調用類方法)。 - 若用戶選擇退出(選項
5
),打印感謝信息并終止循環,結束程序。
代碼優點總結
- 面向對象封裝:將賬戶相關的數據(余額、交易記錄、持有人姓名等)和操作(存款、取款等)封裝在
BankAccount
類中,體現了良好的面向對象設計思想,使代碼結構清晰,便于維護和擴展。 - 輸入校驗完善:在存款、取款等操作中,對用戶輸入的金額進行了充分的有效性檢查(如金額是否為正數、取款時余額是否足夠等),增強了程序的健壯性,避免了不合理操作導致的錯誤。
- 交互友好:通過清晰的菜單提示和操作反饋(如打印存款、取款成功信息和當前余額等),使用戶能夠方便、直觀地與程序進行交互,了解操作結果。
六、__init__
和__str__
是兩個特殊的魔法方法
1.?__init__
?方法
核心作用:
- 構造函數:在創建類實例時自動調用
- 初始化對象:設置對象的初始狀態
銀行賬戶示例:
class BankAccount:def __init__(self, account_holder, initial_balance=0):self.account_holder = account_holder # 設置賬戶持有人self.balance = initial_balance # 設置初始余額self.transactions = [] # 初始化交易記錄
關鍵特點:
- 第一個參數必須是
self
(指向新創建的對象) - 在實例化時自動執行:
account = BankAccount("張三", 1000) # 自動調用__init__
- 不能有返回值(隱式返回
None
)
2.?__str__
?方法
核心作用:
- 定義對象的字符串表示:當使用
print()
或str()
時自動調用 - 提供用戶友好描述:便于調試和輸出
銀行賬戶示例:
def __str__(self):return f"賬戶持有人: {self.account_holder}, 當前余額: {self.balance:.2f}"
使用場景:
account = BankAccount("李四", 500)
print(account) # 自動調用__str__,輸出:賬戶持有人: 李四, 當前余額: 500.00
關鍵特點:
- 必須返回字符串類型
- 如果沒有定義
__str__
,Python會使用__repr__
作為備用 - 常用于日志、用戶界面等需要可讀輸出的場景
3. 對比總結
特性 | __init__ | __str__ |
---|---|---|
調用時機 | 創建實例時 | 調用print() 或str() 時 |
主要用途 | 初始化對象屬性 | 定義對象的可讀字符串表示 |
返回值 | 不應返回任何值 | 必須返回字符串 |
是否必需 | 非必需(但絕大多數類都會實現) | 非必需(但建議重要類都實現) |
示例調用場景 | obj = ClassName(args) | print(obj) ?或?str(obj) |
4. 實際應用關系
在銀行賬戶系統中,這兩個方法協同工作:
# 創建賬戶(調用__init__)
account = BankAccount("王五", 2000) # 查看賬戶信息(調用__str__)
print(account)
# 輸出:賬戶持有人: 王五, 當前余額: 2000.00
5. 為什么需要它們?
-
__init__
: 確保對象創建后即處于有效狀態,避免后續出現屬性未定義的錯誤 -
__str__
: 提供比默認內存地址(如<__main__.BankAccount object at 0x...>
)更有意義的輸出
6. 進階提示
-
類似方法
__repr__
:用于開發者調試,應返回明確的創建表達式
def __repr__(self):return f'BankAccount("{self.account_holder}", {self.balance})'
-
在銀行賬戶系統中,良好的
__str__
實現可以幫助:- 快速查看賬戶狀態
- 生成對賬單摘要
- 調試交易記錄
七、__str__
方法的語言規范
-
必須返回字符串 Python明確規定
__str__
方法必須返回一個字符串對象(str
類型)。當調用print(obj)
或str(obj)
時,解釋器會自動執行這個方法并顯示其返回值。 -
與
print()
的協作機制
print(account) # 內部實際執行:# 1. 調用account.__str__()# 2. 打印該方法返回的字符串
3.銀行賬戶示例解析
def __str__(self):return f"賬戶持有人: {self.account_holder}, 當前余額: {self.balance:.2f}"
-
返回值內容: 返回一個格式化的字符串,包含賬戶持有人和帶兩位小數的余額 (例如:
"賬戶持有人: 張三, 當前余額: 1000.00"
) -
技術細節:
f"..."
:f-string格式化字符串(Python 3.6+):.2f
:將浮點數格式化為2位小數
4.如果不返回字符串會發生什么?
? 錯誤示例:
def __str__(self):print("賬戶信息...") # 錯誤!__str__不應該直接打印
- 調用
print(account)
會導致:?TypeError: __str__ returned non-string (type NoneType)
? 正確做法: 必須通過return
返回字符串,讓調用者決定如何處理這個字符串。
5.為什么不是直接打印?
這種設計體現了關注點分離原則:
-
__str__
的職責: 只負責生成對象的字符串表示形式 (不關心這個字符串是用來打印、記錄日志還是其他用途) -
調用方的自由: 返回字符串后,調用者可以:
# 選擇1:直接打印
print(account)# 選擇2:存入文件
with open("log.txt", "a") as f:f.write(str(account))# 選擇3:拼接其他字符串
msg = "賬戶狀態:" + str(account)
6.類比其他語言
語言 | 類似機制 |
---|---|
Java | toString() ?方法 |
C# | ToString() ?方法 |
JavaScript | toString() ?原型方法 |
C++ | 重載?<< ?操作符 |
八、while True
語句、 if elif else
語句和 try except
語句的詳細介紹
while True
?語句
- 作用:創建一個無限循環,只要條件?
True
?始終滿足(實際上就是一直滿足),循環體就會不斷執行。通常需要在循環內部通過?break
?語句來終止循環。 - 語法結構:
while True:# 循環體代碼if 終止條件:break
- 示例:
while True:user_input = input("請輸入一個數字(輸入 'q' 退出): ")if user_input == 'q':breaktry:num = int(user_input)print(f"你輸入的數字是: {num}")except ValueError:print("輸入無效,請輸入一個整數。")
- 應用場景:
- 創建交互式程序,如命令行工具,等待用戶持續輸入指令,直到用戶發出退出信號(如上述示例)。
- 需要持續監聽某種狀態(如服務器監聽客戶端連接請求)的場景。
if elif else
?語句
- 作用:用于條件判斷,根據不同的條件執行相應的代碼塊。
if
?后面可以跟多個?elif
(表示“否則如果”),最后可以有一個可選的?else
(表示前面條件都不滿足時執行)。 - 語法結構:
if 條件1:# 條件1滿足時執行的代碼
elif 條件2:# 條件2滿足時執行的代碼
else:# 前面條件都不滿足時執行的代碼
- 示例:
score = 85
if score >= 90:print("優秀")
elif score >= 80:print("良好")
elif score >= 60:print("及格")
else:print("不及格")
- 應用場景:
- 根據不同的數值范圍、邏輯條件執行不同操作,如成績等級判斷(如上例)。
- 處理不同用戶角色的權限邏輯(如判斷用戶是管理員、普通用戶等,執行不同的功能)。
try except
?語句
- 作用:用于捕獲和處理程序運行時可能出現的異常,防止程序因為異常而崩潰。
try
?塊中放置可能引發異常的代碼,except
?塊用于處理捕獲到的異常。 - 語法結構:
try:# 可能引發異常的代碼
except 異常類型:# 處理異常的代碼
- 示例:
try:result = 10 / 0 # 會引發 ZeroDivisionError 異常
except ZeroDivisionError:print("除數不能為零!")
- 場景:
- 處理用戶輸入可能不符合預期的情況(如嘗試將用戶輸入轉換為特定類型時,用戶輸入了非數字字符)。
- 進行文件操作、網絡請求等可能失敗的操作時,捕獲并處理相應的異常(如文件不存在?
FileNotFoundError
、網絡連接超時等)。
在實際編程中,這三種語句經常結合使用。例如在銀行賬戶系統代碼里:
while True:try:initial_deposit = float(input("請輸入初始存款金額: "))if initial_deposit < 0:print("初始存款金額不能為負數,請重新輸入")continuebreakexcept ValueError:print("請輸入有效的數字")
這里
while True
創建了一個循環讓用戶不斷輸入,直到輸入有效(通過break
終止循環)。try except
用于處理用戶輸入不是數字的情況(捕獲ValueError
異常),if
語句用于進一步校驗輸入數字的合理性(是否為負數)。
再比如在取款操作的代碼中:
elif choice == "2":# 取款while True:try:amount = float(input("請輸入取款金額: "))if amount <= 0:print("取款金額必須大于0")continueaccount.withdraw(amount)breakexcept ValueError:print("請輸入有效的數字")
九、break
和 continue
是用于控制循環流程的關鍵字
作用和功能
break
- 作用:直接終止當前所在的循環(可以是?
for
?循環或?while
?循環),循環體中?break
?語句之后的代碼將不再執行,程序會跳出循環,繼續執行循環后面的代碼。 - 示例:
- 作用:直接終止當前所在的循環(可以是?
for i in range(10):if i == 5:breakprint(i)
# 輸出結果為 0 1 2 3 4,當 i 等于 5 時,循環終止
continue
- 作用:跳過本次循環中?
continue
?語句之后的代碼,直接進入下一次循環的條件判斷(對于?for
?循環,會繼續迭代下一個元素;對于?while
?循環,會繼續判斷循環條件)。 - 示例:
- 作用:跳過本次循環中?
for i in range(10):if i % 2 == 0:continueprint(i)
# 輸出結果為 1 3 5 7 9,當 i 是偶數時,跳過本次循環的打印操作,直接進入下一次循環
適用場景
break
- 當你在循環中發現某個特定條件滿足,并且后續不需要再執行循環中的任何操作時,就可以使用?
break
?來提前結束循環。例如在一個列表查找元素的循環中,一旦找到目標元素,就可以用?break
?停止繼續查找。 - 示例:
- 當你在循環中發現某個特定條件滿足,并且后續不需要再執行循環中的任何操作時,就可以使用?
my_list = [10, 20, 30, 40, 50]
target = 30
for num in my_list:if num == target:print(f"找到目標元素 {target}")break
continue
- 當你希望在滿足某些條件時,跳過本次循環的一部分操作,但循環還需要繼續執行下去時,適合使用?
continue
。比如在遍歷一個數字列表時,想忽略其中的偶數,只對奇數進行某些計算或處理。 - 示例
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for num in numbers:if num % 2 == 0:continue # 跳過偶數# 以下是對奇數的處理邏輯print(f"處理奇數: {num}")
對循環嵌套的影響
break
:在循環嵌套的情況下,break
?只會終止它所在的那一層循環。- 示例:
for i in range(5):for j in range(5):if j == 2:break # 只會跳出內層的 j 循環print(f"i={i}, j={j}")
# 輸出結果是 當 j 等于 2 時,內層循環停止,外層循環繼續
continue
:同樣在循環嵌套中,continue
?也只影響它所在的那一層循環,會跳過該層循環中?continue
?后面的代碼,進入該層循環的下一次迭代。- 示例:
for i in range(5):for j in range(5):if j == 2:continue # 跳過內層 j 循環中 j=2 時后續的代碼,繼續 j 的下一次循環print(f"i={i}, j={j}")
# 輸出結果是 當 j 等于 2 時,跳過本次 j 循環的打印操作,j 繼續遞增
總的來說,break
用于快速結束循環,continue
用于有條件地跳過循環體中的部分代碼,它們為程序員提供了靈活控制循環流程的手段。