|
|
发表于 2024-11-17 00:24:27
|
显示全部楼层
0.
子類別可以重寫父類別的方法
1.
在函式中不會看你傳入內容的型別,有相關方法就會操作
2.
可以,這是運算子的多型
3.
有一隻鳥走起路來像鴨子、叫聲也像鴨子,就會把牠當成鴨子
4.
高內聚低耦合,是判斷軟體設計好壞的標準。在程式設計中,我們都希望盡可能做到高內聚(內聚,Cohesion是從功能角度來衡量模組內部的關聯性,一個好的內聚模組應該只負責完成一件事,它描述的是模組內的功能聯繫)和低耦合(耦合coupling,是軟體結構中各模組之間相互連結的一種衡量,耦合的強弱取決於模組間介面的複雜程度、進入或存取某個模組的方式以及透過介面傳遞的資料)。那麼請問,使用鴨子型別,是增強了內聚還是降低了耦合度呢?
降低了耦合度
內聚 (Cohesion)
定義:
內聚是衡量模組內部功能元素之間相關性的一個指標。內聚越高,模組內部的功能元素越緊密地聚合在一起,越能有效完成特定的單一任務。
特徵:
高內聚的模組通常專注於完成一件事,功能單一且明確。
模組內的程式碼彼此高度相關,改變某一部分時,影響範圍僅限於該模組內部。
高內聚可以提升程式的可維護性、可讀性,並降低未來擴展或修改的複雜度。
內聚的種類(從低到高):
偶然性內聚:模組內的功能幾乎無關聯,僅是偶然放在一起。
邏輯性內聚:模組內的功能通過邏輯條件來選擇執行,但彼此不直接相關。
時間性內聚:模組內的功能在同一時間段執行,僅因執行時序相同而組合。
程序性內聚:模組內的功能依執行程序先後排列,彼此有一定依賴。
通訊性內聚:模組內的功能操作同一資料集,具有共通目標。
功能性內聚:模組專注於完成單一明確的任務,最高級別的內聚。
耦合 (Coupling)
定義:
耦合是衡量不同模組之間相互依賴程度的一個指標。耦合越低,模組間的關聯越鬆散,彼此獨立性越高。
特徵:
模組間的耦合性越低,模組的獨立性越高,系統的靈活性和可擴展性越好。
耦合高則表示模組間依賴過多,改動一個模組可能會導致連鎖反應,影響其他模組。
耦合的種類(從高到低):
內容耦合:一個模組直接存取或修改另一模組的內部資料或邏輯,最壞的情況。
共用耦合:多個模組共同存取同一全域資料,增加潛在衝突。
外部耦合:模組依賴於外部的介面、裝置或資料格式。
控制耦合:一個模組控制另一模組的行為(例如傳遞控制旗標)。
資料耦合:模組間僅透過簡單資料結構(如參數)進行交換,關聯性較低。
訊息耦合:模組間僅透過訊息(例如呼叫方法或函數)交換資料,是最低的一種耦合。
內聚與耦合的關係
高內聚和低耦合是理想的程式設計目標。
高內聚確保模組內部功能集中,改動影響範圍小。
低耦合減少模組間的依賴性,增加系統靈活性和可維護性。
二者是一體兩面:提升內聚通常可以幫助降低耦合,反之亦然。例如,功能單一的模組自然不需要與太多外部模組交互,耦合性也會隨之降低。
簡單比喻
內聚可以理解為團隊的專業度,每個人專注於自己的工作。
耦合則是團隊之間的合作關係,彼此不需要過多干涉,但可以有效協作。
一個成功的專案需要團隊專業度(高內聚)和團隊間協作效率(低耦合)兼顧。
5.
這不算,只是傳進去值然後z有預設值而已
動手:
0.
以下是我目前的程式碼,尚未完成
請提示我該修改的地方,僅提示即可,不要直接給我程式碼
class Employee:
def __init__(self, name, job, year, grade, uid):
self.name = name
self.job = job
self.grade = grade
self.year = year
self.uid = uid
def get_uid(self):
return self.uid
def get_name(self):
return self.name
def get_job(self):
return self.job
def get_grade(self):
return self.grade
def get_year(self):
return self.year
def salary(self, grade, year): #計算工資
salary = 3000 + 500 * grade + 50 * year
return salary
class Teamleader(Employee):
def salary(self, grade, year):
salary = 4000 + 800 * grade + 100 * year
return salary
class Manager(Employee):
def salary(self, grade, year):
salary = 5000 + 1000 * (grade + year)
return salary
class Check():
def num_error(arg):
try:
int(arg)
return arg
except:
print("請輸入正確的數字")
return False
def grade_check(grade, job):
if job == "E":
limit = 10
elif job == "T":
limit = 6
elif job == "M":
limit = 3
if 0 < grade <= limit:
return grade
else:
print(f"該職位最高級別為{limit},請重新輸入")
return False
def upgrade_check(job, grade):
if job == "E":
limit = 10
elif job == "T":
limit = 6
elif job == "M":
limit = 3
if 0 < grade <= limit:
return job, grade
if grade > limit:
if job == "E":
job = "T"
elif job == "T":
job = "M"
grade = 1
return job, grade
class Func(Check):
def __init__(self):
self.members = {}
self.uid = 10000
# 程式功能入口
def main_func(self):
while ins != '5':
ins = input("\n1.輸入資料;2.查詢資料;3.升級;4.降級;5.退出程式:")
if ins == '1':
self.record_emp()
if ins == '2':
self.search_emp()
if ins == '3':
self.upgrade()
if ins == '4':
self.downgrade()
if ins == '5':
print("已退出員工管理系統")
def record_emp(self): #輸入員工資料
name = input("姓名:")
job = input("職位:(E.普通員工;T.組長;M.經理)").upper()
while not year:
year = input("工齡:")
year = Check.num_error(year)
while not grade:
grade = input("級別:")
grade = Check.num_error(grade)
grade = Check.grade_check(grade, job)
uid = self.uid
emp = Employee(name, job, year, grade, uid)
self.members[uid] = emp #記錄到members字典
self.salary = self.salary(grade, year)
print(f"輸入成功!姓名:{self.name},工號:{self.uid},薪資:{self.salary}")
self.uid += 1 #輸入一次就改一次卡號
def search_emp(self):
search_opt = input("1.員工查詢;2.職位查詢")
if search_opt == "1":
uid = input("請輸入工號:")
while not self.members.get(uid):
uid = int(input("該工號不存在,請重新輸入:"))
else:
print(f'''姓名:{self.members.get(uid).name}\n
職位:{self.members.get(uid).job}\n
級別:{self.members.get(uid).grade}\n
工齡:{self.members.get(uid).year}\n
薪資:{self.members.get(uid).salary()}\n''')
elif search_opt == "2":
total_value = self.members.values()
job_input = input("請輸入職位:(E.普通員工;T.組長;M.經理)").upper()
if job == "E":
title = "普通員工"
elif job == "T":
title = "組長"
elif job == "M":
title = "經理"
count = total_value.count(f"{job_input}")
if count:
print(f"目前{title}共有{count}人:")
else:
print(f"目前公司沒有{title}!")
for job in self.members.values():
if job == job_input:
print(f"{self.members.get(uid)} - {self.members.get(uid).name}")
else:
("輸入錯誤,請重新輸入")
def upgrade(self):
uid = input("請輸入工號:")
while not self.members.get(uid):
uid = int(input("該工號不存在,請重新輸入:"))
else:
print(f'''{self.members.get(uid).name},
工號:{self.members.uid},
目前職位:{self.members.get(uid).job}{self.members.get(uid).grade}
目前薪資:{self.members.get(uid).salary()}''')
while not grade_up:
grade_up = input("請輸入需要增加的級數:")
grade_up = Check.num_error(grade_up)
else:
grade = self.members.get(uid).grade + int(grade_up)
job = self.members.get(uid).job
job, grade = Check.upgrade_check(job, grade)
old_salary = self.members.get(uid).salary()
self.members[uid]['job'] = job
self.members[uid]['grade'] = grade
print("升級成功!")
new_salary = self.members.get(uid).salary()
print(f'''{self.members.get(uid).name},
工號:{self.members.uid},
升級後職位:{self.members.get(uid).job}{self.members.get(uid).grade}
升級後薪資:{new_salary}({new_salary - old_salary})''')
def downgrade(self):
pass
def main():
f = Func()
f.main_func()
GPT:
1. 子類 Teamleader 和 Manager 的 salary 方法不需要傳參數
父類的 salary() 方法接受 grade 和 year 作為參數,但這些值已經是物件屬性,因此不需要傳入參數。
修改點:覆寫的 salary() 方法中,直接使用 self.grade 和 self.year。
2. 子類應該初始化基類屬性
Teamleader 和 Manager 應使用 super().__init__() 初始化父類的屬性,避免重複定義。
正確的繼承關係
super().__init__() 確保子類正確初始化基類中的所有屬性和行為,維持物件的一致性。如果你跳過 super().__init__(),子類可能缺失某些基類的邏輯,導致非預期的問題。
3.
3. 檢查和更新 record_emp() 中對子類的處理
record_emp() 中未區分不同職位的員工。當輸入職位時,應根據 job 值創建對應類型的物件 (Employee, Teamleader, Manager)。
確保薪資計算時準確使用到該用的方法
4. 修正薪資計算和顯示
record_emp() 中的 self.salary 呼叫方式錯誤。應該呼叫 emp.salary() 方法,而非 self.salary。
修改點:將 self.salary = self.salary(grade, year) 改為 salary = emp.salary()。
我沒有在基類設置self.salary也可以這樣寫嗎?要設置會更好嗎?
emp.salary()跟self.salary() 差別在哪?
1. emp.salary() 和 self.salary() 的差別
emp.salary():
這裡的 emp 是動態創建的物件(可能是 Employee 或其子類,例如 Teamleader 或 Manager)。
當你調用 emp.salary() 時,會根據物件的實際類型,執行該類型的 salary() 方法。例如:
如果 emp 是 Teamleader,則會執行 Teamleader.salary() 方法。
如果 emp 是 Manager,則會執行 Manager.salary() 方法。
這利用了多態特性,能正確地計算不同職位員工的薪資。
self.salary():
這指的是當前類的 salary() 方法。
如果 record_emp() 是在 Func 類中,self.salary() 指的是 Func 類的 salary() 方法(如果存在)。
如果 Func 類沒有定義 salary() 方法,這樣的調用會導致錯誤。
因此,emp.salary() 是正確的寫法,因為 emp 指向具體的員工物件,而薪資計算邏輯與員工的職位類型(子類)相關。
2. 是否需要在基類設置 self.salary
不一定需要在基類設置 self.salary,但根據你的需求,是否設置取決於以下情況:
不設置 self.salary 的情況
薪資是動態計算的,並不需要保存為物件屬性。例如,你每次需要時都調用 emp.salary() 即可:
適用於薪資計算簡單、對薪資查詢頻率不高的場景。
設置 self.salary 的情況
如果你需要頻繁查詢薪資,或薪資的計算比較複雜且成本較高(例如需要從資料庫讀取或涉及大量運算),保存計算結果為屬性會更高效
5. search_emp() 有錯誤的邏輯和變數使用
self.members.get(uid) 返回的是一個物件,不是字典,無法使用 self.members[uid]['job'] 來存取。
修改點:
查詢屬性時應直接從物件存取,例如:self.members[uid].job。
修正職位計數邏輯,應遍歷 self.members.values() 判斷 job 屬性。
1. self.members.get(uid) 返回的值
self.members.get(uid) 的返回值不是 list,而是你之前存入字典的員工物件。
self.members 是一個字典:
其中的鍵(key)是工號(uid),值(value)是員工的物件(如 Employee, Teamleader, Manager)。
當你執行 self.members.get(uid) 時,返回的是 uid 對應的值,也就是一個員工物件。例如:
emp = self.members.get(10001)
# emp 是一個員工物件,可能是 Employee 或其子類
2. self.members[uid].job 的存取邏輯
當 self.members[uid] 返回員工物件時,你可以通過點操作符存取該物件的屬性,例如 job:
class Employee:
def __init__(self, name, job, year, grade, uid):
self.name = name
self.job = job
self.year = year
self.grade = grade
self.uid = uid
# 假設 self.members 結構如下:
self.members = {
10001: Employee(name="Alice", job="E", year=5, grade=3, uid=10001),
10002: Teamleader(name="Bob", job="T", year=7, grade=2, uid=10002),
10003: Manager(name="Charlie", job="M", year=10, grade=1, uid=10003),
}
# 存取工號為 10001 的員工職位
emp = self.members[10001] # emp 是 Employee(name="Alice", ...)
print(emp.job) # 輸出 "E"
3. 修正職位計數邏輯,遍歷 self.members.values()
問題所在: 你在查詢職位時,嘗試直接統計字典中是否有符合的職位:
count = total_value.count(f"{job_input}")
但 self.members 的值是員工物件,而不是職位字串,這樣統計會報錯或返回錯誤的結果。
正確方式: 需要遍歷 self.members.values(),檢查每個物件的 job 屬性是否與輸入職位相符。以下是詳細邏輯:
job_input = input("請輸入職位:(E.普通員工;T.組長;M.經理)").upper()
# 遍歷所有員工物件,統計符合條件的職位
count = sum(1 for emp in self.members.values() if emp.job == job_input)
self.members.values():返回字典中所有的值(即所有員工物件)。
for emp in self.members.values():迴圈遍歷每個員工物件。
if emp.job == job_input:判斷該員工的 job 是否等於輸入的職位。
sum(1 for ...):每當條件成立時,將 1 加到總數中,最終返回符合條件的員工數量。
請問self.members.get(uid)和emp.members[uid]兩種寫法有什麼不同?我要如何判斷在存取字典內容時,什麼時候用emp什麼時候用self?
1. self.members.get(uid) 與 self.members[uid] 的差別
1.1 self.members.get(uid)
是 字典的安全存取方法。
當鍵 uid 存在於字典中時,返回該鍵對應的值(例如員工物件)。
當鍵 uid 不存在時,默認返回 None,不會拋出錯誤。
你可以指定一個默認值,如果鍵不存在,返回該默認值。例如:
emp = self.members.get(uid, "Not Found")
1.2 self.members[uid]
是 字典的直接存取方式。
當鍵 uid 存在時,返回該鍵對應的值。
當鍵 uid 不存在時,會拋出 KeyError 錯誤。
用法總結:
用 self.members.get(uid) 當:
不確定鍵是否存在,並且希望避免程式崩潰時。
想要在鍵不存在時設置默認值。
用 self.members[uid] 當:
確定鍵一定存在,並且希望在鍵缺失時得到即時的錯誤提示(例如調試時使用)。
self
self 是指向當前類的實例。
在你的程式中,self.members 表示的是管理所有員工資料的字典,它是 Func 類的一部分:
因此,self.members 表示這個類別物件所擁有的員工資料,存放了所有員工的工號(鍵)和對應的員工物件(值)。
emp
emp 是在函數或程式區塊內的局部變數,通常代表某個具體的員工物件。
當你查詢某個工號並取得對應員工物件時,會將它賦值給變數 emp:
emp = self.members.get(uid)
此時,emp 是某個特定員工的物件,並非存放所有員工資料的字典。
3.1 使用 self
當你要操作的是「所有員工」相關的資料,應使用 self.members。
例子:
新增員工:self.members[uid] = emp
查詢所有員工:for emp in self.members.values()
查找特定工號:emp = self.members.get(uid)
3.2 使用 emp
當你已經取得某個具體的員工物件,並要操作該物件的屬性或方法時,應使用 emp。
例子:
查詢某員工的職位:emp.job
計算某員工的薪資:emp.salary()
修改某員工的屬性:emp.grade = new_grade
修改版:
class Employee:
def __init__(self, name, job, year, grade, uid):
self.name = name
self.job = job
self.grade = grade
self.year = year
self.uid = uid
def get_uid(self):
return self.uid
def get_name(self):
return self.name
def get_job(self):
return self.job
def get_grade(self):
return self.grade
def get_year(self):
return self.year
def salary(self): #計算工資
salary = 3000 + 500 * self.grade + 50 * self.year
return salary
class Teamleader(Employee):
def __init__():
super().__init__()
def salary(self):
salary = 4000 + 800 * self.grade + 100 * self.year
return salary
class Manager(Employee):
def __init__():
super().__init__()
def salary(self):
salary = 5000 + 1000 * (self.grade + self.year)
return salary
class Check():
def num_error(arg):
try:
int(arg)
return arg
except:
print("請輸入正確的數字")
return False
def grade_check(grade, job):
if job == "E":
limit = 10
elif job == "T":
limit = 6
elif job == "M":
limit = 3
if 0 < grade <= limit:
return grade
else:
print(f"該職位最高級別為{limit},請重新輸入")
return False
def upgrade_check(job, grade):
if job == "E":
limit = 10
elif job == "T":
limit = 6
elif job == "M":
limit = 3
if 0 < grade <= limit:
return job, grade
if grade > limit:
if job == "E":
job = "T"
elif job == "T":
job = "M"
grade = 1
return job, grade
class Func(Check):
def __init__(self):
self.members = {}
self.uid = 10000
# 程式功能入口
def main_func(self):
while ins != '5':
ins = input("\n1.輸入資料;2.查詢資料;3.升級;4.降級;5.退出程式:")
if ins == '1':
self.record_emp()
if ins == '2':
self.search_emp()
if ins == '3':
self.upgrade()
if ins == '4':
self.downgrade()
if ins == '5':
print("已退出員工管理系統")
else:
print("輸入錯誤,請重新輸入")
def record_emp(self): #輸入員工資料
name = input("姓名:")
job = input("職位:(E.普通員工;T.組長;M.經理)").upper()
while not year:
year = input("工齡:")
year = Check.num_error(year)
while not grade:
grade = input("級別:")
grade = Check.num_error(grade)
grade = Check.grade_check(grade, job)
uid = self.uid
#根據職別建立不同實例化物件
if job == "E":
emp = Employee(name, job, year, grade, uid)
elif job == "T":
emp = Teamleader(name, job, year, grade, uid)
elif job == "M":
emp = Manager(name, job, year, grade, uid)
self.members[uid] = emp #記錄到members字典
print(f"輸入成功!姓名:{self.members.get(uid).name},工號:{self.members.get(uid).uid},薪資:{emp.salary()}")
self.uid += 1 #輸入一次就改一次卡號
def search_emp(self):
search_opt = input("1.員工查詢;2.職位查詢")
if search_opt == "1":
uid = input("請輸入工號:")
uid = Check.num_error(uid)
while not self.members.get(uid):
uid = int(input("該工號不存在,請重新輸入:"))
else:
print(f'''姓名:{self.members.get(uid).name}\n
職位:{self.members.get(uid).job}\n
級別:{self.members.get(uid).grade}\n
工齡:{self.members.get(uid).year}\n
薪資:{self.members.get(uid).salary()}\n''')
elif search_opt == "2":
total_value = self.members.values()
job_input = input("請輸入職位:(E.普通員工;T.組長;M.經理)").upper()
if job == "E":
title = "普通員工"
elif job == "T":
title = "組長"
elif job == "M":
title = "經理"
count = sum(1 for emp in self.members.values() if emp.job == job_input)
if count:
print(f"目前{title}共有{count}人:")
else:
print(f"目前公司沒有{title}!")
for job in self.members.values():
if job == job_input:
print(f"{self.members.get(uid)} - {self.members.get(uid).name}")
else:
("輸入錯誤,請重新輸入")
def upgrade(self):
uid = input("請輸入工號:")
uid = Check.num_error(uid)
while not self.members.get(uid):
uid = int(input("該工號不存在,請重新輸入:"))
else:
print(f'''{self.members.get(uid).name},
工號:{self.members.uid},
目前職位:{self.members.get(uid).job}{self.members.get(uid).grade}
目前薪資:{self.members.get(uid).salary()}''')
while not grade_up:
grade_up = input("請輸入需要增加的級數:")
grade_up = Check.num_error(grade_up)
else:
grade = self.members.get(uid).grade + int(grade_up)
job = self.members.get(uid).job
job, grade = Check.upgrade_check(job, grade)
old_salary = self.members.get(uid).salary()
self.members.get(uid).job = job
self.members.get(uid).grade = grade
print("升級成功!")
new_salary = self.members.get(uid).salary()
print(f'''{self.members.get(uid).name},
工號:{uid},
升級後職位:{self.members.get(uid).job}{self.members.get(uid).grade}
升級後薪資:{new_salary}({new_salary - old_salary})''')
def downgrade(self):
pass
def main():
f = Func()
f.main_func()
GPT:
1. Teamleader 和 Manager 的建構子 (__init__)
目前,Teamleader 和 Manager 的 __init__ 方法尚未正確定義。應該接收與 Employee 一樣的參數,並使用 super() 初始化基類。
class Teamleader(Employee):
def __init__(self, name, job, year, grade, uid):
super().__init__(name, job, year, grade, uid)
class Manager(Employee):
def __init__(self, name, job, year, grade, uid):
super().__init__(name, job, year, grade, uid)
5. 搜尋功能 (search_emp)
search_emp 方法的 職位查詢 部分存在錯誤:
變數 job 未定義,應使用 job_input。
列印員工資訊時,self.members.get(uid) 是錯誤的,因為 uid 在該上下文未定義。
改進建議:
在 for 循環中正確使用員工物件。 範例:
for emp in self.members.values():
if emp.job == job_input:
print(f"{emp.uid} - {emp.name}")
改:
class Employee:
def __init__(self, name, job, year, grade, uid):
self.name = name
self.job = job
self.grade = grade
self.year = year
self.uid = uid
def get_uid(self):
return self.uid
def get_name(self):
return self.name
def get_job(self):
return self.job
def get_grade(self):
return self.grade
def get_year(self):
return self.year
def salary(self): #計算工資
salary = 3000 + 500 * self.grade + 50 * self.year
return salary
class Teamleader(Employee):
def __init__(self, name, job, year, grade, uid):
super().__init__(name, job, year, grade, uid)
def salary(self):
salary = 4000 + 800 * self.grade + 100 * self.year
return salary
class Manager(Employee):
def __init__(self, name, job, year, grade, uid):
super().__init__(name, job, year, grade, uid)
def salary(self):
salary = 5000 + 1000 * (self.grade + self.year)
return salary
class Check():
def num_error(arg):
try:
int(arg)
return arg
except:
print("請輸入正確的數字")
return False
def grade_check(grade, job):
if job == "E":
limit = 10
elif job == "T":
limit = 6
elif job == "M":
limit = 3
if 0 < grade <= limit:
return grade
else:
print(f"該職位最高級別為{limit},請重新輸入")
return False
def updown_grade_check(job, grade, change):
if job == "E":
limit = 10
elif job == "T":
limit = 6
elif job == "M":
limit = 3
if 0 < grade <= limit:
return job, grade
if grade > limit:
if job == "E":
job = "T"
elif job == "T":
job = "M"
grade = 1
return job, grade
if 0 > grade:
if job == "M":
job = "T"
grade = 6
elif job == "T":
job = "E"
grade = 10
return job, grade
class Func(Check):
def __init__(self):
self.members = {}
self.uid = 10000
# 程式功能入口
def main_func(self):
while ins != '5':
ins = input("\n1.輸入資料;2.查詢資料;3.升級;4.降級;5.退出程式:")
if ins == '1':
self.record_emp()
if ins == '2':
self.search_emp()
if ins == '3' or '4':
self.up_downgrade()
if ins == '5':
print("已退出員工管理系統")
else:
print("輸入錯誤,請重新輸入")
def record_emp(self): #輸入員工資料
name = input("姓名:")
job = input("職位:(E.普通員工;T.組長;M.經理)").upper()
while not year:
year = input("工齡:")
year = Check.num_error(year)
while not grade:
grade = input("級別:")
grade = Check.num_error(grade)
grade = Check.grade_check(grade, job)
uid = self.uid
#根據職別建立不同實例化物件
if job == "E":
emp = Employee(name, job, year, grade, uid)
elif job == "T":
emp = Teamleader(name, job, year, grade, uid)
elif job == "M":
emp = Manager(name, job, year, grade, uid)
self.members[uid] = emp #記錄到members字典
print(f"輸入成功!姓名:{self.members.get(uid).name},工號:{self.members.get(uid).uid},薪資:{emp.salary()}")
self.uid += 1 #輸入一次就改一次卡號
def search_emp(self):
search_opt = input("1.員工查詢;2.職位查詢")
if search_opt == "1":
uid = input("請輸入工號:")
uid = Check.num_error(uid)
while not self.members.get(uid):
uid = int(input("該工號不存在,請重新輸入:"))
else:
print(f'''姓名:{self.members.get(uid).name}\n
職位:{self.members.get(uid).job}\n
級別:{self.members.get(uid).grade}\n
工齡:{self.members.get(uid).year}\n
薪資:{self.members.get(uid).salary()}\n''')
elif search_opt == "2":
total_value = self.members.values()
job_input = input("請輸入職位:(E.普通員工;T.組長;M.經理)").upper()
if job_input == "E":
title = "普通員工"
elif job_input == "T":
title = "組長"
elif job_input == "M":
title = "經理"
count = sum(1 for emp in self.members.values() if emp.job == job_input)
if count:
print(f"目前{title}共有{count}人:")
else:
print(f"目前公司沒有{title}!")
for emp in self.members.values():
if emp.job == job_input:
print(f"{emp.uid} - {emp.name}")
else:
("輸入錯誤,請重新輸入")
def up_downgrade(self):
uid = input("請輸入工號:")
uid = Check.num_error(uid)
while not self.members.get(uid):
uid = int(input("該工號不存在,請重新輸入:"))
else:
print(f'''{self.members.get(uid).name},
工號:{self.members.uid},
目前職位:{self.members.get(uid).job}{self.members.get(uid).grade}
目前薪資:{self.members.get(uid).salary()}''')
while not grade_change:
grade_change = input("請輸入需要變更的級數,降級請加上負號:")
grade_change = Check.num_error(grade_change)
else:
grade = self.members.get(uid).grade + int(grade_change)
job = self.members.get(uid).job
job, grade = Check.updown_grade_check(job, grade)
old_salary = self.members.get(uid).salary()
self.members.get(uid).job = job
self.members.get(uid).grade = grade
print("調整成功!")
new_salary = self.members.get(uid).salary()
print(f'''{self.members.get(uid).name},
工號:{uid},
調整後職位:{self.members.get(uid).job}{self.members.get(uid).grade}
調整後薪資:{new_salary}({new_salary - old_salary})''')
def main():
f = Func()
f.main_func()
GPT:
Check 類中的方法實際上不依賴於類的屬性,屬於純工具函數,適合作為靜態方法。
建議: 將 Check 類中的方法設為 @staticmethod,並修復 num_error 返回正確數字的問題。
class Check:
@staticmethod
def num_error(arg):
try:
return int(arg)
except ValueError:
print("請輸入正確的數字")
return False
在主選單中,if ins == '3' or '4': 的判斷條件總是返回 True,因為 '4' 作為非空字串評估為真。
建議:
修改條件判斷為正確的形式,並加上 elif,避免執行多個不相關的分支。
year 和 grade 未初始化,會導致 while not year 報錯。
year, grade = None, None
grade_change 未初始化,while not grade_change 會報錯。
=================
if __name__ == "__main__":
main() # 執行主程式入口
這樣加入後出現了UnboundLocalError:ins referenced before assignment
問題原因
在你的 main_func 方法中,這部分代碼有問題:
while ins != '5':
ins = input("\n1.輸入資料;2.查詢資料;3.升級;4.降級;5.退出程式:")
這裡的 ins 是局部變數,但在 while 條件中先被引用,此時它尚未初始化。
這會導致 Python 嘗試在本地範圍內查找 ins,但找不到,因此報錯。
解決方案
在 main_func 方法中,先初始化變數 ins,例如:
ins = "" # 初始化變數,避免未賦值錯誤
*
目前在升降級時輸入id後會出現'dict' object has no attribute 'uid'
問題原因:self.members 是一個字典,並沒有屬性 uid。正確的做法應該是操作字典中對應的具體員工物件。
*
我想在輸入員工資料的地方加上防呆措施
while True:
job = input("職位(E.普通員工;T.組長;M.經理):").upper()
if job != "E" and "T" and "M":
print("輸入錯誤,請重新輸入!")
else:
break
但目前這樣寫即使輸入M也會不斷重複輸入錯誤
請問有什麼問題?
if job != "E" and "T" and "M":
在 Python 中,這段條件的解釋是:
job != "E" 是一個布林判斷,結果可能為 True 或 False。
"T" 和 "M" 是非空字串,在布林上下文中總是為 True。
所以條件實際上等價於:
if (job != "E") and True and True:
這導致無論 job 為何值,條件始終會被判定為 True。
正確解決方案
要檢查 job 是否不是 "E"、"T" 或 "M",應該使用括號或 not in 運算符。
解法 1:使用 not in
改寫為:
while True:
job = input("職位(E.普通員工;T.組長;M.經理):").upper()
if job not in ["E", "T", "M"]:
print("輸入錯誤,請重新輸入!")
else:
break
解法 2:使用多重條件(不建議)
while True:
job = input("職位(E.普通員工;T.組長;M.經理):").upper()
if job != "E" and job != "T" and job != "M":
print("輸入錯誤,請重新輸入!")
else:
break
為什麼推薦 not in
可讀性高:job not in ["E", "T", "M"] 直觀地表達了 job 是否不屬於該列表。
可擴展性高:如果將來需要檢查更多合法輸入,只需在列表中添加項目。
1. 工資計算的邏輯與職位不匹配
你在更新 job 和 grade 後,薪資計算依然沿用了之前的職位邏輯,而沒有使用正確的 salary() 方法。
在 Python 中,如果員工對象是 Employee,但更新為組長或經理時,對象的 salary() 方法仍然是 Employee 類的方法,而不是更新後職位的薪資計算邏輯。
self.members 中的對象類型沒有動態變更
在調整職位(升降/降級)時,job 變更了,但對應對象的類型並沒有改變。這會導致 salary() 方法仍然使用舊的類型邏輯。
解決方案
方法 1:根據 job 更新對象類型
當職位變更時,重新實例化對象,並替換 self.members 中的對象。
改:
class Employee:
def __init__(self, name, job, year, grade, uid):
self.name = name
self.job = job
self.grade = grade
self.year = year
self.uid = uid
def get_uid(self):
return self.uid
def get_name(self):
return self.name
def get_job(self):
return self.job
def get_grade(self):
return self.grade
def get_year(self):
return self.year
def salary(self): #計算工資
salary = 3000 + 500 * self.grade + 50 * self.year
return salary
class Teamleader(Employee):
def __init__(self, name, job, year, grade, uid):
super().__init__(name, job, year, grade, uid)
def salary(self):
salary = 4000 + 800 * self.grade + 100 * self.year
return salary
class Manager(Employee):
def __init__(self, name, job, year, grade, uid):
super().__init__(name, job, year, grade, uid)
def salary(self):
salary = 5000 + 1000 * (self.grade + self.year)
return salary
class Check():
def num_error(arg):
try:
return int(arg)
except:
print("請輸入正確的數字")
return False
def grade_check(grade, job):
if job == "E":
limit = 10
elif job == "T":
limit = 6
elif job == "M":
limit = 3
if 0 < grade <= limit:
return grade
else:
print(f"該職位最高級別為{limit},請重新輸入!")
return False
def updown_grade_check(job, grade):
if job == "E":
limit = 10
elif job == "T":
limit = 6
elif job == "M":
limit = 3
if 0 < grade <= limit:
return job, grade
if grade > limit:
if job == "E":
job = "T"
elif job == "T":
job = "M"
grade = 1
return job, grade
if 0 > grade:
if job == "M":
job = "T"
grade = 6
elif job == "T":
job = "E"
grade = 10
return job, grade
def change_job(self, job, grade, uid):
# 根據新職位重新創建對象
if job == "E":
self.members[uid] = Employee(
name=self.members[uid].name,
job=job,
year=self.members[uid].year,
grade=grade,
uid=uid,
)
elif job == "T":
self.members[uid] = Teamleader(
name=self.members[uid].name,
job=job,
year=self.members[uid].year,
grade=grade,
uid=uid,
)
elif job == "M":
self.members[uid] = Manager(
name=self.members[uid].name,
job=job,
year=self.members[uid].year,
grade=grade,
uid=uid,
)
class Func(Check):
def __init__(self):
self.members = {}
self.uid = 10000
# 程式功能入口
def main_func(self):
ins = ""
while ins != '5':
ins = input("\n1.輸入資料;2.查詢資料;3.升級;4.降級;5.退出程式:")
if ins == '1':
self.record_emp()
elif ins == '2':
if self.members == {}:
print("目前尚未輸入任何員工資料")
else:
self.search_emp()
elif ins == '3':
if self.members == {}:
print("目前尚未輸入任何員工資料")
else:
self.up_downgrade()
elif ins == '4':
if self.members == {}:
print("目前尚未輸入任何員工資料")
else:
self.up_downgrade()
elif ins == '5':
print("已退出員工管理系統")
else:
print("輸入錯誤,請重新輸入")
def record_emp(self): #輸入員工資料
name = input("姓名:")
while True:
job = input("職位(E.普通員工;T.組長;M.經理):").upper()
if job not in ["E", "T", "M"]:
print("輸入錯誤,請重新輸入!")
else:
break
year, grade = None, None
while not year:
year = input("工齡:")
year = Check.num_error(year)
while not grade:
grade = input("級別:")
grade = Check.num_error(grade)
grade = Check.grade_check(grade, job)
uid = self.uid
#根據職別建立不同實例化物件
if job == "E":
emp = Employee(name, job, year, grade, uid)
elif job == "T":
emp = Teamleader(name, job, year, grade, uid)
elif job == "M":
emp = Manager(name, job, year, grade, uid)
self.members[uid] = emp #記錄到members字典
print(f"輸入成功!姓名:{self.members.get(uid).name},工號:{self.members.get(uid).uid},薪資:{emp.salary()}")
self.uid += 1 #輸入一次就改一次卡號
def search_emp(self):
search_opt = ""
while not search_opt:
search_opt = input("1.員工查詢;2.職位查詢:")
if search_opt == "1":
while not uid:
uid = input("請輸入工號:")
uid = Check.num_error(uid)
if not self.members.get(uid):
print("該工號不存在,請重新輸入:")
else:
print(f'姓名:{self.members.get(uid).name}\n'
f'職位:{self.members.get(uid).job}\n'
f'級別:{self.members.get(uid).grade}\n'
f'工齡:{self.members.get(uid).year}\n'
f'薪資:{self.members.get(uid).salary()}')
break
elif search_opt == "2":
job_input = input("請輸入職位(E.普通員工;T.組長;M.經理):").upper()
if job_input == "E":
title = "普通員工"
elif job_input == "T":
title = "組長"
elif job_input == "M":
title = "經理"
else:
print("輸入錯誤,請重新輸入")
count = sum(1 for emp in self.members.values() if emp.job == job_input)
if count:
print(f"目前{title}共有{count}人:")
else:
print(f"目前公司沒有{title}!")
for emp in self.members.values():
if emp.job == job_input:
print(f"{emp.uid} - {emp.name}")
else:
print("輸入錯誤,請重新輸入")
break
def up_downgrade(self):
uid = ""
while not uid:
uid = input("請輸入工號:")
uid = Check.num_error(uid)
if not self.members.get(uid):
print("該工號不存在,請重新輸入!")
else:
print(f'''{self.members.get(uid).name},工號:{uid},目前職位:{self.members.get(uid).job}{self.members.get(uid).grade},目前薪資:{self.members.get(uid).salary()}''')
old_salary = self.members.get(uid).salary()
grade_change = None
while not grade_change:
grade_change = input("請輸入需要變更的級數,降級請加上負號:")
grade_change = Check.num_error(grade_change)
else:
grade = self.members.get(uid).grade + int(grade_change)
job = self.members.get(uid).job
job, grade = Check.updown_grade_check(job, grade)
if job != self.members.get(uid).job:
self.change_job(job, grade, uid)
new_salary = self.members[uid].salary()
print("調整成功!")
new_salary = self.members.get(uid).salary()
print(f'{self.members.get(uid).name}\n'
f'工號:{uid}\n'
f'調整後職位:{self.members.get(uid).job}{self.members.get(uid).grade}\n'
f'調整後薪資:{new_salary}({new_salary - old_salary:+})\n')
def main():
f = Func()
f.main_func()
if __name__ == "__main__":
main() # 執行主程式入口
1. 修正 change_job 方法的作用域問題
目前,change_job 是 Check 類的方法,而 self.members 是 Func 類的屬性,因此 Check 方法中無法直接訪問 self.members。這會導致 AttributeError。
解決方案:
將 change_job 方法移動到 Func 類中,或者將 self.members 作為參數傳遞進入。
2. 防止未初始化變數的潛在錯誤
問題: uid 和 year 等變數在一些方法中可能未初始化
例如,在 search_emp 中,uid 和 search_opt 如果沒有初始化可能導致錯誤。
3. 精簡輸出,避免重複代碼
多處重複輸出的邏輯可以抽取到單獨的方法中,提升代碼可讀性和重用性。
新增方法 print_employee_info
def print_employee_info(self, uid):
emp = self.members.get(uid)
if emp:
print(f'姓名:{emp.name}\n'
f'職位:{emp.job}\n'
f'級別:{emp.grade}\n'
f'工齡:{emp.year}\n'
f'薪資:{emp.salary()}')
最終:
class Employee:
def __init__(self, name, job, year, grade, uid):
self.name = name
self.job = job
self.grade = grade
self.year = year
self.uid = uid
def get_uid(self):
return self.uid
def get_name(self):
return self.name
def get_job(self):
return self.job
def get_grade(self):
return self.grade
def get_year(self):
return self.year
def salary(self): #計算工資
salary = 3000 + 500 * self.grade + 50 * self.year
return salary
class Teamleader(Employee):
def __init__(self, name, job, year, grade, uid):
super().__init__(name, job, year, grade, uid)
def salary(self):
salary = 4000 + 800 * self.grade + 100 * self.year
return salary
class Manager(Employee):
def __init__(self, name, job, year, grade, uid):
super().__init__(name, job, year, grade, uid)
def salary(self):
salary = 5000 + 1000 * (self.grade + self.year)
return salary
class Check():
def num_error(arg):
try:
return int(arg)
except:
print("請輸入正確的數字")
return False
def grade_check(grade, job):
if job == "E":
limit = 10
elif job == "T":
limit = 6
elif job == "M":
limit = 3
if 0 < grade <= limit:
return grade
else:
print(f"該職位最高級別為{limit},請重新輸入!")
return False
def updown_grade_check(job, grade):
if job == "E":
limit = 10
elif job == "T":
limit = 6
elif job == "M":
limit = 3
if 0 < grade <= limit:
return job, grade
if grade > limit:
if job == "E":
job = "T"
elif job == "T":
job = "M"
grade = 1
return job, grade
if 0 > grade:
if job == "M":
job = "T"
grade = 6
elif job == "T":
job = "E"
grade = 10
return job, grade
class Func(Check):
def __init__(self):
self.members = {}
self.uid = 10000
# 程式功能入口
def main_func(self):
ins = ""
while ins != '5':
ins = input("\n1.輸入資料;2.查詢資料;3.升級;4.降級;5.退出程式:")
if ins == '1':
self.record_emp()
elif ins == '2':
if self.members == {}:
print("目前尚未輸入任何員工資料")
else:
self.search_emp()
elif ins == '3':
if self.members == {}:
print("目前尚未輸入任何員工資料")
else:
self.up_downgrade()
elif ins == '4':
if self.members == {}:
print("目前尚未輸入任何員工資料")
else:
self.up_downgrade()
elif ins == '5':
print("已退出員工管理系統")
else:
print("輸入錯誤,請重新輸入")
def record_emp(self): #輸入員工資料
name = input("姓名:")
while True:
job = input("職位(E.普通員工;T.組長;M.經理):").upper()
if job not in ["E", "T", "M"]:
print("輸入錯誤,請重新輸入!")
else:
break
year, grade = None, None
while not year:
year = input("工齡:")
year = Check.num_error(year)
while not grade:
grade = input("級別:")
grade = Check.num_error(grade)
grade = Check.grade_check(grade, job)
uid = self.uid
#根據職別建立不同實例化物件
if job == "E":
emp = Employee(name, job, year, grade, uid)
elif job == "T":
emp = Teamleader(name, job, year, grade, uid)
elif job == "M":
emp = Manager(name, job, year, grade, uid)
self.members[uid] = emp #記錄到members字典
print(f"輸入成功!姓名:{self.members.get(uid).name},工號:{self.members.get(uid).uid},薪資:{emp.salary()}")
self.uid += 1 #輸入一次就改一次卡號
def search_emp(self):
search_opt = None
uid = None
while not search_opt:
search_opt = input("1.員工查詢;2.職位查詢:")
if search_opt == "1":
while not uid:
uid = input("請輸入工號:")
uid = Check.num_error(uid)
if not self.members.get(uid):
print("該工號不存在,請重新輸入:")
else:
print(f'姓名:{self.members.get(uid).name}\n'
f'職位:{self.members.get(uid).job}\n'
f'級別:{self.members.get(uid).grade}\n'
f'工齡:{self.members.get(uid).year}\n'
f'薪資:{self.members.get(uid).salary()}')
break
elif search_opt == "2":
job_input = input("請輸入職位(E.普通員工;T.組長;M.經理):").upper()
if job_input == "E":
title = "普通員工"
elif job_input == "T":
title = "組長"
elif job_input == "M":
title = "經理"
else:
print("輸入錯誤,請重新輸入")
count = sum(1 for emp in self.members.values() if emp.job == job_input)
if count:
print(f"目前{title}共有{count}人:")
else:
print(f"目前公司沒有{title}!")
for emp in self.members.values():
if emp.job == job_input:
print(f"{emp.uid} - {emp.name}")
else:
print("輸入錯誤,請重新輸入")
break
def up_downgrade(self):
uid = None
while not uid:
uid = input("請輸入工號:")
uid = Check.num_error(uid)
if not self.members.get(uid):
print("該工號不存在,請重新輸入!")
else:
print(f'''{self.members.get(uid).name},工號:{uid},目前職位:{self.members.get(uid).job}{self.members.get(uid).grade},目前薪資:{self.members.get(uid).salary()}''')
old_salary = self.members.get(uid).salary()
grade_change = None
while not grade_change:
grade_change = input("請輸入需要變更的級數,降級請加上負號:")
grade_change = Check.num_error(grade_change)
else:
grade = self.members.get(uid).grade + int(grade_change)
job = self.members.get(uid).job
job, grade = Check.updown_grade_check(job, grade)
if job != self.members.get(uid).job:
self.change_job(job, grade, uid)
new_salary = self.members[uid].salary()
print("調整成功!")
new_salary = self.members.get(uid).salary()
print(f'{self.members.get(uid).name}\n'
f'工號:{uid}\n'
f'調整後職位:{self.members.get(uid).job}{self.members.get(uid).grade}\n'
f'調整後薪資:{new_salary}({new_salary - old_salary:+})\n')
def change_job(self, job, grade, uid):
# 根據新職位重新創建對象
if job == "E":
self.members[uid] = Employee(
name=self.members[uid].name,
job=job,
year=self.members[uid].year,
grade=grade,
uid=uid,
)
elif job == "T":
self.members[uid] = Teamleader(
name=self.members[uid].name,
job=job,
year=self.members[uid].year,
grade=grade,
uid=uid,
)
elif job == "M":
self.members[uid] = Manager(
name=self.members[uid].name,
job=job,
year=self.members[uid].year,
grade=grade,
uid=uid,
)
def main():
f = Func()
f.main_func()
if __name__ == "__main__":
main() # 執行主程式入口
|
|