學習了一些Python的基礎知識之后,就開始來實踐吧。
上手非常簡單,有過一定編程經驗的人大約可以在幾個小時之內掌握基本的Python編程方法。
正好在學習設計模式課程,會有幾次課程作業,就直接拿過來權當Python的一次編程練習了
第一次任務簡介:
實現一個管理雇員薪水的工具,可以打印出員工的薪水信息。
雇員分為普通和經理,各自有不同的薪水計算方法。
Ok,Let's go!
首先復習一下Python里的面向對象相關知識,定義一個雇員的基類EmployeeBase
并且在__init__方法里定義了三個成員name, base_salary和overtime_days
需要注意的就是所有的類成員方法在聲明的時候都需要有一個默認的參數self,這個相當于this指針的東西必須要寫上,而且訪問類成員或者方法也都要加上這個前綴,不然會出錯。
1?class?EmployeeBase():
2?????"""Base?class?of?all?staffs"""
3?????def?__init__(self,?name?=?"",?basesalary?=?0,?overtime?=?0):
4?????????self.name?=?name
5?????????self.base_salary?=?basesalary
6?????????self.overtime_days?=?overtime
7?????def?GetName(self):
8?????????return?self.name
接下來就是普通雇員類Employee,繼承的語法:
Employee(EmployeeBase)
以及類的__doc__,養成寫注釋的習慣。
Line 6:
__init__并不是構造函數,并且Python里也沒有構造函數這個概念。所以要手動的調用基類的__init__方法GetSalary中計算薪水,普通雇員的加班工資是雙倍計算的。
?1?class?Employee(EmployeeBase):
?2?????"""Common?employee?class?derived?from?EmployeeBase.
?3?????A?employee?can?has?overtime?salary,?every?overtime?work's?salary?will?be?doubled
?4?????"""
?5?????def?__init__(self,?name="",?basesalary=0,?overtime=0):
?6???????? EmployeeBase.__init__(self,name,basesalary,overtime)
?7?????def?GetStaffType(self):
?8?????????return?"Employee"
?9?????def?GetSalary(self):
10?????????return?self.base_salary?+?self.base_salary/30*2*self.overtime_days
11?????def?GetSalaryInfo(self):
12?????????return?self.name?+?"?:?"?+?self.GetStaffType()+?"?:?"?+?str(self.GetSalary())
到這里,雇員類已經完成,下面就是——
單元測試。一般我以前寫程序都很少寫單元測試的,因為很費時,要寫很多測試的代碼。
但是這里我想特別嘗試一下,以展現Python里的各種特性和工具。
新版本的Python里有一個專門用于測試的unittest模塊,導入就可以使用了,下面新建一個Testsalary.py進行單元測試。
首先unittest模塊里有一個測試用例的基類
TestCase,我們只要在TestCase的派生類里定義自己的測試用例方法就可以使用了,這些測試用命方法甚至都不需要自己調用,只要方法
名字以test開頭,TestCase就會自動的調用它們。
在下面的測試代碼中,我定義了testNoneEmployee等幾個測試方法,主要是使用了TestCase里的
assertEqual方法。
"""Unit?test?for?salary.py"""
import?unittest
from salary importEmployee
class?TestEmployee(unittest.TestCase):
????"""Unit?test?for?clas?Employee"""
????def?testNoneEmployee(self):
????????e?=?Employee()
????????self.assertEqual("",e.GetName())
????????self.assertEqual(0,e.GetSalary())
????????self.assertEqual("Employee",e.GetStaffType())
????def?testBaseSalary(self):
????????e?=?Employee("emp",?300)
????????self.assertEqual("emp",e.GetName())
????????self.assertEqual(300,e.GetSalary())
????????self.assertEqual("Employee",e.GetStaffType())
????def?testNoOvertime(self):
????????e?=?Employee("emp",?300,?0)
????????self.assertEqual(300,e.GetSalary())
????????self.assertEqual("emp?:?Employee?:?300",?e.GetSalaryInfo())
????def?testOvertime1(self):
????????e?=?Employee("emp",?300,?1)
????????self.assertEqual(320,e.GetSalary())
????????self.assertEqual("emp?:?Employee?:?320",?e.GetSalaryInfo())
????def?testOvertime2(self):
????????e?=?Employee("emp",?300,?5)
????????self.assertEqual(400,e.GetSalary())
????????self.assertEqual("emp?:?Employee?:?400",?e.GetSalaryInfo())
????????
if?__name__?==?"__main__":
????unittest.main()
運行之,出現結果:
----------------------------------------------------------------------
Ran 5 tests?in?0.007s
OK
全部通過,太沒意思了,想著要加點什么好呢。下面我對構造Employee的時候加上參數的檢查,不允許不正確的參數輸入,例如名字太長,工資和加班天數為負數等。我希望在試圖用這些不正確的參數進行創建Employee對象的時候出現異常。
在測試代碼中加入另兩個方法,使用了TestCase里的另一個方法
assertRaises,這個方法可以檢測被測對象是否按拋出了預期的異常。這個方法接受一個異常類型,和一個會產生這種異常的“對象”,通常是一個函數,以及它們的參數
????def?testInvalidName(self):
????????self.assertRaises(InvalidName,?Employee,?"name?too?long")
????def?testInvalidInput1(self):
????????self.assertRaises(InvalidInput,?Employee,?"emp",?-300)
????def?testInvalidInput2(self):
????????self.assertRaises(InvalidInput,?Employee,?"emp",?300,?-5)
兩種異常類的名字分別叫InvalidName和InvalidInput,這下測試通不過了。下面就需要修改Employee類,首先提一下Python里的異常處理,使用try...except...處理異常,raise拋出異常,finally可以用來做一些善后處理工作。
下面先要定義上面用到的這兩種異常,InvalidName和InvalidInput,這里簡單的繼承一下Python里的Exception類就可以了,然后修改Employee的__init__方法,進行參數的查檢,修正后如下:
#new?type?of?Expceptions
class?InvalidName(Exception):pass
class?InvalidInput(Exception):pass
#----------------------
????def?__init__(self,?name="",?basesalary=0,?overtime=0):
????????#raise?exceptions?if?input?is?invalidate
????????if?len(name)?>?8:
????????????raise?InvalidName,?"Error:?Name?too?long!"
????????if?basesalary?<?0?or?basesalary?>?300000:
????????????raise?InvalidInput,?"Error:?Base?salary?should?between?0~300000!"
????????#use?int(overtime)?!=?overtime?to?check?if?the?input?is?int
????????if?overtime?<?0?or?overtime??>?31?or?int(overtime)?!=?overtime:
????????????raise?InvalidInput,?"Error:?Overtime?should?between?0~31!"
????????EmployeeBase.__init__(self,name,basesalary,overtime)
ps:異常類型后面的文字是為了給,異常處理提供信息用的。
OK,第一步順利完成,下面就是經理類。經理的工資由加班工資和績效組成,加班工資只跟經理的等級有關,它與績效工資都是一個固定值,基本上沒有什么難度。