1、什么是類
- 人類、車類、鳥類、猴類、生物類
- 是一群具有相同 特征 或者 相同行為的事物的一個統稱,是抽象的
- Python中的類可以類比為圖紙(模子)
- 類只有一個
- 特征:一般是名詞,特性, Python中稱為屬性
- 行為: 一般為動作,Python中稱為方法(類似於函數)
2、什么是對象
- 人類:男人 女人 性別不詳的人
- 鳥類:麻雀 孔雀 鳳凰 鴕鳥
- 對象是一個具體的存在:鳳凰
- 對象是由類創建的,並且具有類的特征和行為
- 對象有很多個,可以使用類來創建多個對象
- 每個對象之間,擁有不同的屬性值
- 每個對象的實例屬性是獨有的
2.1對象的概念
某種數據類型的一個具體的數據,個體,對象,就稱之為這個類的一個實例或者對象。
比如:1就是整數的一個實例/對象
通過類創建對象叫實例化。
所謂的面向對象,就是把一些數據抽象成類的思想。
3.定義類class
# 類名為大駝峰 class PeopleInfo: """ 定義人類 """ # 類中稱為方法 # 類似於函數 def __init__(self, name, age, sex): # 構造方法, 構造器 pass
4.
- 在類中創建的方法,如果帶 self, 那么往往把它叫做實例方法
- 創建對象,是一個實例化的過程
- 使用 對象.方法名 來調用方法
- 對象將自身, 自動傳給了self, 所以不會報錯, 在類里面, self 相當於one_person
- 在類的外面創建屬性, ---不推薦使用
- 使用 對象.屬性 = 屬性值 類似於給變量賦值
- 在類的外面如何調用屬性
- 使用 對象.屬性 類似於獲取變量
class PersonInfo: # 類相當於圖紙(模板) """ 定義人類 """ def run(self): # self跟調用方法時的對象ID一致 print("人會跑步") def eat(self): # 在類中創建的方法, 如果帶self, 那么往往把它叫做實例方式 print("人會吃飯") one_person = PersonInfo() # 創建對象(蓋房子), 是一個實例化的過程 print(f"one_person的ID為: {id(one_person)}") one_person.run() # 使用 對象.方法名 來調用方法 one_person.eat() # 對象將自身, 自動傳給了self, 所以不會報錯, 在類里面, self相當於one_person # 在類的外面創建屬性, ---不推薦使用 # 使用 對象.屬性 = 屬性值 類似於給變量賦值 one_person.name = "胡巴" one_person.age = 25 one_person.height = 190 # 在類的外面如何調用屬性 # 使用 對象.屬性 類似於獲取變量 print(one_person.name) print(one_person.age) print(one_person.height)
類屬性:
- 共有的特征, 那么叫做類屬性
- 在類的外面定義的是變量,但是在類名的下面。定義的變量,稱為類屬性,所以對象共有的特征
類的初始化函數__init__:
- 固定形式, 絕大多數情況下, 會使用__init__方法來創建屬性,稱為構造方法或者構造器, 推薦做法
- 形參,由類名("雨欣") 來傳參實參
- 在構造方法下創建屬性,寫死:self.fair = "假發"
- 一般在類的里面, 會使用 self.屬性 來創建屬性:self.name = name
__str__:魔術方法
- 如果使用print函數打印一個對象, 那么會自動調用__str__實例方法
- _str__實例方法,需要返回一個字符串,否則會報錯
- 使用return來定義
-
def __str__(self): # 魔術方法 return "<{}>".format(self.name)
在類中創建的方法,如果帶 self, 那么往往把它叫做實例方法
可以使用類來創建多個對象,每個對象之間,擁有不同的屬性值,每個對象的實例屬性是獨有的
class PersonInfo: # 類相當於圖紙(模板) """ 定義人類 """ # 共有的特征, 那么叫做類屬性 head = 1 # 在類的外面定義的是變量, 但是在類名的下面, 定義的變量, 稱為類屬性, 所以對象共有的特征 def __init__(self, name, age, height): """ 固定形式, 絕大多數情況下, 會使用__init__方法來創建屬性,稱為構造方法或者構造器, 推薦做法 :param name:形參,由類名("雨欣") 來傳參實參 :param age:形參,由類名(16) 來傳參實參 :param height:形參,由類名(170) 來傳參實參 """ self.fair = "假發" # 創建屬性,寫死 self.name = name # 一般在類的里面, 會使用 self.屬性 來創建屬性 self.age = age self.height = height print(f"self的ID為: {id(self)}") # 在類的里面使用self.屬性名, 能獲取屬性的值 print("姓名: {}\n年齡: {}\n身高: {}".format(self.name, self.age, self.height)) def run(self): # self跟調用方法時的對象ID一致,實例方法中,使用self.屬性名 來調用 # self.face = "瓜子" # 實例方法中創建屬性--不推薦 print("{}會跑步".format(self.name)) def eat(self): # 在類中創建的方法, 如果帶self, 那么往往把它叫做實例方法 print("{}會吃飯".format(self.name)) def info(self): # 在類的里面, 可以使用類名.類屬性 來獲取類屬性的值 # print("姓名: {}\n年齡: {}\n身高: {}\n腦袋個數: {}".format(self.name, self.age, self.height, PersonInfo.head)) # 在類的里面, 可以使用self.類屬性 來獲取類屬性的值 print("姓名: {}\n年齡: {}\n身高: {}\n腦袋個數: {}".format(self.name, self.age, self.height, self.head)) def __str__(self): # 魔術方法 # 如果使用print函數打印一個對象, 那么會自動調用__str__實例方法 # 往往__str__實例方法, 需要返回一個字符串 return "<{}>".format(self.name) # 可以使用類來創建多個對象 # 每個對象之間, 擁有不同的屬性值 # 每個對象的實例屬性是獨有的 one_person = PersonInfo("雨欣", 16, 180) # 類名() 默認會調用__init__方法,實參 two_person = PersonInfo("Sunny", 18, 185) # one_person.run() # two_person.run() # two_person.eat() print(one_person) print(two_person) # 在類的外面如何訪問類屬性? # 1. 類名.類屬性 print(PersonInfo.head) # 2. 對象.類屬性 print(one_person.head) print(two_person.head) # PersonInfo.info() # 不能使用類名來調用實例方法 # PersonInfo.name # 不能使用類名來調用實例屬性 one_person.info() # 可以使用對象名來調用實例方法
5.類方法和靜態方法
類方法
格式:
@classmethod # (譯:可拉斯.蠻色的)裝飾器,類方法來處理類屬性的 def angray(cls): # 如果不加裝飾器,默認創建實例方法 cls.head = 2 pass
- 使用@classmethod來定義(譯:卡拉斯.蠻色的)
- 在類方法里面 調用 或 修改 類屬性 -------cls.類屬性
- 在類中創建的方法, 如果帶self, 那么它叫做實例方法
- 在類的外面可以調用靜態方法
- 對象.靜態方法
- 類.靜態方法
- 在外面,來調實例屬性
- 對象.實例屬性
- 在外面,調用類屬性
- 對象.類屬性
- 在外面,調用類方法
- 對象.類方法
- 當對象調用類方法時, 會把對象所屬的類ID自動賦值給cls
- 在類的外面修改類屬性--不推薦
- 類名.類屬性
- 對象不能調用類外面的函數
- 對象.函數名
靜態方法
格式:
@staticmethod # (譯:四大題刻.蠻色的 )定義的是靜態方法, 靜態跟類外面定義的函數幾乎沒有區別, 只不過是位置不同以 def weather_forecase(motion): """ 播報天氣 在類的外面定義的一定是函數, 在類的里面定義的才是方法 :return: """ print("天氣, 晴朗!") print("溫度: 22°") print("適合出游")
- 使用@staticmethod來定義
- 在類的外面調用靜態方法
- 對象.靜態方法
- 類.靜態方法
- 在類的里面調用靜態方法
- self.靜態方法
- 在類里面的類方法內調用靜態方法
- cls.靜態方法
- 在類的里面可以調用類外面的函數
問題:
1、實例方法和類方法、靜態方法有什么區別?
1、第一個參數:實例方法是 self,類方法是 cls,靜態方法沒有必傳參數。
2、類方法用 @classmethod 裝飾。靜態方法用 @staticmethod 裝飾。
3、實例方法,一定要有對象能訪問。
類方法,不需要對象直接類名訪問,類和對象都可以訪問。
靜態方法,對象和類都可以訪問。
函數與方法:
類當中定義的函數,叫做方法
不在類當中定義的函數。
一定要有實例化對象才能訪問的。
實例屬性:
定義的時候:self.屬性名 = 值
調用的時候:對象名.屬性名
實例方法:
定義的時候:方法的第一參數是self
調用的時候:對象名.方法名(有參傳參)
在實例方法當中,可不可以通過self調用其它的實例方法???
可以
注意:方法不要互相調用
知識點:
實例屬性,都在__init__方法中定義初始值。
實例方法,第一個參數必須是self。在實例方法當中,可以修改實例屬性的值。
6.類的內部和外部調用
代碼案例:
class NumDeal: num_type = '數字類型' num_amount1 = 11 num_amount2 = 33 def __init__(self, num1, num2): self.num1 = num1 self.num2 = num2 print(f'類內部調用類方法nums_sum:{self.nums_sum()}') # 類內部調用類方法,因為創建了兩次實例對象,所以調用該方法時傳入兩個對象的實例變量值 print(f'類內部調用實例方法nums_add:{self.nums_add()}') # 類內部調用類方法,因為創建了兩次實例對象,所以調用該方法時傳入兩個對象的實例變量值 print(f'類的內部調用實例屬性num1:{self.num1},num2:{self.num2}') # 因為創建了兩個實例化對象,所以會調用初始化函數兩次,分別打印出兩個對象分別傳入的值 print(f'類的內部調用類屬性num_type:{self.num_type},num_amount1:{self.num_amount1},num_amount2:{self.num_amount2}') def nums_add(self): # 實例方法 return self.num1 + self.num2 @classmethod # 定義類方法需要用裝飾器@classmethod def nums_sum(cls): # 類方法 return cls.num_amount1 + cls.num_amount2 num_int = NumDeal(4, 5) num_float = NumDeal(4.1, 5.1) print('*'*30, 'num_int', '*'*30) print(f'類外邊通過類實例對象num_int調用類屬性:{num_int.num_type}') print(f'類外邊通過類實例對象num_int調用實例屬性num1:{num_int.num1},num2:{num_int.num2}') print(f'類外邊通過類實例對象num_int調用實例方法nums_add(兩個int類型數字相加結果):{num_int.nums_add()}') print(f'類外邊通過類實例對象num_int調用類方法nums_sum():{num_int.nums_sum()}') print() print('*'*30, 'num_float', '*'*30) print(f'類外邊通過類實例對象num_float調用類屬性:{num_float.num_type}') print(f'類外邊通過類實例對象num_float調用實例屬性num1:{num_float.num1},num2:{num_float.num2}') print(f'類外邊通過類實例對象num_float調用實例方法nums_add(兩個float類型數字相加結果):{num_float.nums_add()}') print(f'類外邊通過類實例對象num_float調用類方法nums_sum():{num_float.nums_sum()}') print() print('*'*30, 'NumDeal', '*'*30) print(f'類外邊通過類名NumDeal調用類屬性:{NumDeal.num_type}') # print(f'類外邊通過類名NumDeal調用實例屬性num1:{NumDeal.num1}') # 會報錯,說明不能用類名調用實例屬性 # print(f'類外邊通過類名NumDeal調用實例方法nums_add():{NumDeal.add()}')#會報錯,說明不能用類名調用實例方法 # print(f'類外邊通過類名NumDeal調用實例方法nums_add(:{NumDeal.nums_add(num_int)}') # 可以在調用實例方法是傳入類實例對象 print(f'類外邊通過類名NumDeal調用類方法nums_sum():{NumDeal.nums_sum()}')
執行結果:
類內部調用類方法nums_sum:44 類內部調用實例方法nums_add:9 類的內部調用實例屬性num1:4,num2:5 類的內部調用類屬性num_type:數字類型,num_amount1:11,num_amount2:33 類內部調用類方法nums_sum:44 類內部調用實例方法nums_add:9.2 類的內部調用實例屬性num1:4.1,num2:5.1 類的內部調用類屬性num_type:數字類型,num_amount1:11,num_amount2:33 ****************************** num_int ****************************** 類外邊通過類實例對象num_int調用類屬性:數字類型 類外邊通過類實例對象num_int調用實例屬性num1:4,num2:5 類外邊通過類實例對象num_int調用實例方法nums_add(兩個int類型數字相加結果):9 類外邊通過類實例對象num_int調用類方法nums_sum():44 ****************************** num_float ****************************** 類外邊通過類實例對象num_float調用類屬性:數字類型 類外邊通過類實例對象num_float調用實例屬性num1:4.1,num2:5.1 類外邊通過類實例對象num_float調用實例方法nums_add(兩個float類型數字相加結果):9.2 類外邊通過類實例對象num_float調用類方法nums_sum():44 ****************************** NumDeal ****************************** 類外邊通過類名NumDeal調用類屬性:數字類型 類外邊通過類名NumDeal調用類方法nums_sum():44
1、實例屬性
在類的外面
-
- 賦值(創建)
- 對象.屬性名-------不推薦
- 類.實例屬性名 = 屬性值
- 錯誤用法,執行報錯
- 調用
- 對象.屬性名
- 類.實例屬性名 = 屬性值
- 錯誤用法,執行報錯
- 賦值(創建)
在類的里面
-
- 賦值(創建)
- 使用__init__方法來給實例實例屬性賦值
- self.屬性名 = 屬性值
- cls.實例屬性名 = 屬性值
- 錯誤用法,執行報錯
- 調用
- self.屬性名
- cls.實例屬性名
- 錯誤用法,執行報錯
- 賦值(創建)
2、類屬性
在類的外面
-
- 賦值(創建)
- 類名.類屬性名 = 類屬性值
- 對象.類屬性名 = 類屬性值
- 錯誤用法,執行報錯
- 調用
- 類名.類屬性名
- 對象.類屬性名
- 賦值(創建)
在類的里面
-
- 賦值(創建)
- 類名.類屬性名 = 類屬性值
- cls.類屬性名 = 類屬性值
- self.類屬性名 = 類屬性值
- 錯誤用法,執行報錯
- 調用
- 類名.類屬性名
- cls.類屬性名
- self.類屬性名
- 賦值(創建)
3、實例方法
在類的外面
-
- 調用
- 對象.實例方法()
- 類名.實例方法()
- 錯誤用法,執行報錯
- 調用
在類的里面
-
- 賦值(創建)
- 類名.類屬性名 = 類屬性值
- cls.類屬性名 = 類屬性值
- self.類屬性名 = 類屬性值
- 錯誤用法,執行報錯
- 調用
- self.實例方法()
- 類名.實例方法()
- 錯誤用法,執行報錯
- cls.實例方法()
- 錯誤用法,執行報錯
- 賦值(創建)
4、類方法
在類的外面
-
- 調用
- 類名.類方法()
- 對象.類方法()
- 調用
在類的里面
-
- 調用
- 類名.類方法()
- self.類方法()
- 調用
5、靜態方法
在類的外面
-
- 調用
- 類名.靜態方法(參數)
- 對象.靜態方法(參數)
- 調用
在類的里面
-
- 調用
- 類名.靜態方法(參數)
- self.靜態方法(參數)
- cls.靜態方法(參數)
- 調用
7.類的繼承、重寫、拓展、超繼承
繼承:
- 子類可以直接調用繼承的父類中的屬性值:self/name
- 使用類名(父類名) 來繼承父類的所有方法, 私有方法和私用屬性除外(__one_methond)
- 被繼承也可以叫做:父類、超類、基類
- 繼承父類的類叫做:子類
私有屬性/方法
1、不想被子類繼承
2、不想被外部訪問
3、私有屬性/方法,僅在類內部。
私有化的屬性/方法:僅給類內部使用。
私有化的方式:
1、_屬性/方法: 子類/對象都可以訪問_屬性/方法,但是,不希望被訪問。
2、__屬性/方法: 子類/對象不可以訪問__屬性/方法。 雙下划綫級別會更高
class Parent: def __init__(self, id): print("我是爸爸,我有財產。我的id是{}".format(id)) self._flag = "漲薪3000" # 定義私有化屬性 self.__flag = "漲薪3000" def run(self): print("爸爸會跑!!!") # 類內部訪問私有屬性 def print_flage(self): print(self.__flag) # 繼承 - 擁有父類的所有方法 class Son(Parent): def print_money(self): print(self._flag) # 可以打印出來,但是 . 的時候沒有聯想 print(self.__flag) # 子類/對象不可以訪問__屬性/方法。 s = Son(1111111) s.run() # print(s._flag) # 可以打印出來,但是 . 的時候沒有聯想 # print(s.__flag) # 會報錯,提示沒有這個屬性 s.print_money() # 會報錯,子類/對象不可以訪問__屬性/方法。
重寫:super().父類方法
- 對父類方法的重寫,如果定義了跟父類一樣的方法名,那么會將父類同名的方法覆蓋掉
- 重寫后,子類調用的是重寫后的實例方法
- super().父類方法,能夠調用父類的方法,是Python3中的方法,重寫
繼承之后,對於父類已有的方法,進行重寫 (改進父類的同名方法、全面顛覆父類的同名方法)。
在子類當中,調用父類的同名方法:super
super().父類的同名方法(有參傳參)
因為如果使用 self 去調,就會直接調用子類的同名方法。
就近原則:子類有的方法,直接使用子類。子類沒有的方法,才去父類找。
class Parent: def __init__(self, id): print("我是爸爸,我有財產。我的id是{}".format(id)) def run(self): print("爸爸會跑!!!") def sleep(self, place): print("在 {} 休息".format(place)) # 繼承之后,要對父類的同名方法,進行優化。。 class Son(Parent): # 通常會去調用父類的初始化方法,並額外增加子類想要做的初始化代碼。 # 父類的__init__參數必須有,可以額外再添加其它參數。 def __init__(self, my_id): super().__init__(my_id) # 調用 父類的方法 print("我是兒砸,我是女兒!!") # self.run() # 如果與父類不重名,一般都是通過self去調用 # super().run() def sleep(self, my_place, pet_name): super().sleep(my_place) # super 調用 父類的方法 print("和{}一起!!".format(pet_name)) s = Son(1234567890) # s.run() s.sleep("公司", "老板家的狗子") # 繼承之后,不對父類作任何改動,僅僅在父類的基礎上,增加了其它的方法 class Son2(Parent): def eat(self): print("會吃!!!") def cooking(self): print("做飯666666") def sport(self): print("開始運動!") self.run()
多重繼承:了解
class Grand: def run(self): print("爺爺會跑!!!") class Parent(Grand): def __init__(self,id): print("我是爸爸,我有財產。我的id是{}".format(id)) def run(self): print("爸爸會跑!!!") def sleep(self,place): print("在 {} 休息".format(place)) # 繼承之后,要對父類的同名方法,進行優化。。 class Son(Parent): # 通常會去調用父類的初始化方法,並額外增加子類想要做的初始化代碼。 # 父類的__init__參數必須有,可以額外再添加其它參數。 def __init__(self,my_id): super().__init__(my_id) print("我是兒砸,我是女兒!!") # self.run() # 如果與父類不重名,一般都是通過self去調用 # super().run() def sleep(self,my_place, pet_name): super().sleep(my_place) print("和{}一起!!".format(pet_name)) def run(self): super().run() # 就近原則 Son(1111111).run()
多繼承
class Student: def study(self): print("學習,投資自己") class Employee: def own_money(self): print("賺錢") class People(Student, Employee): def run(self): print("會跑") People().study()
拓展:
拓展,,在父類的方法的基礎上,新增內容;super().__init__ 代表父類,代表創建了對象調用了 init方法
超繼承:
def info(self): # 定義與父類同樣的方法 # super()能夠調用父類的方法, 是Python3中的方法 super().info() # 調用父類的方法 print("工作: {}".format(self.job)) # 在本子類中添加新的內容,即繼承了父類中的方法,也添加了新的內容
示例:
class Animal(object): # 如果一個類, 沒有顯示繼承一個類, 那么默認會繼承object(祖宗類) """ 定義動物類 :object 寫與不寫都一樣,如果一個類, 沒有顯示繼承一個類, 那么默認會繼承object(祖宗類) """ def __init__(self, name, age, color): self.name = name self.age = age self.color = color def eat(self): print("{}需要吃東西".format(self.name)) def drink(self): print("{}需要喝水".format(self.name)) def run(self): print("{}會跑步".format(self.name)) def sleep(self): print("{}需要睡覺".format(self.name)) def info(self): print("姓名: {}\n年齡: {}\n顏色: {}".format(self.name, self.age, self.color)) class Dog(Animal): """ 使用類名(父類名) 來繼承父類的所有方法, 私有方法和私用屬性除外(__one_methond) 被繼承的類也可以叫做:父類、超類、基類;繼承父類的類叫做子類 """ def bark(self): print("{}會汪汪叫".format(self.name)) class XiaoTianQuan(Dog): def __init__(self, name, age, color, job): # 拓展, 在父類的方法的基礎上, 新增內容;super().__init__ 代表父類,代表創建了對象調用了 init方法 self.name = name self.age = age self.color = color super().__init__(name, age, color) self.job = job def fly(self): print("{}會飛".format(self.name)) def sleep(self): # 對父類方法的重寫,如果定義了跟父類一樣的方法名, 那么會將父類同名的方法覆蓋掉 print("{}是神仙, 不需要睡覺".format(self.name)) def info(self): # Python2中, 可以使用super(子類名, self).父類的方法 super(XiaoTianQuan, self).info() # super().父類方法,能夠調用父類的方法, 是Python3中的方法,重寫 super().info() print("工作: {}".format(self.job)) class Cat(Animal): def catch(self): print("{}會抓老鼠".format(self.name)) if __name__ == '__main__': taidi = Dog("泰迪", 1, '黑色') taidi.weight = 2 # 動態創建屬性, 比較少見, 也有應用場景 xiaotianquan = XiaoTianQuan("哮天犬", 1000, "金色") xiaotianquan = XiaoTianQuan("哮天犬", 1000, "金色", "守護天庭") taidi.info() xiaotianquan.sleep() # 重寫方法:將父類的方法覆蓋掉 xiaotianquan.info()
多態:了解
python沒有多態,python處處皆多態 -- python的函數,參數不需要申明類型,也不會限定類型。
python: 鴨子類型
Java語言:函數的任意參數,必須申明是什么類型。傳參一定要是指定的數據類型,否則就報錯。
多態:父類類型,接收子類對象。
# 父類 class People: def run(self): print("人會跑") # 子類 class Student(People): def run(self): print("學生會跑") # 子類 class Employee(People): def run(self): print("員工會跑") class Dunk: def run(self): print("鴨子會跑") # python當中函數的參數 def can_run(obj): obj.run() e1 = Employee() # 判斷e1是不是Employee類的對象, e1是不是Employee父類People的對象?? print(isinstance(e1, Employee)) # True print(isinstance(e1, People)) # True # e1 = Employee() # # 對象作為函數的參數 # can_run(e1) # # can_run("hello world") # s1 = Student() # # 對象作為函數的參數 # can_run(s1) # # p1 = People() # # 對象作為函數的參數 # can_run(p1) # # d1 = Dunk() # # 對象作為函數的參數 # can_run(d1)
重載:了解
java語言:
1、函數的參數,必須指定數據類型
2、函數的參數,沒有不定長類型。
解決:
1、同一函數名,參數支持不同的數據類型。
--- python而言,參數類型不受限制。
2、同一函數名,支持參數個數不一樣。
--- python而言,*args, **kwargs
# 別的語言java: 參數是個整數 def hello_world(int a): print("11111") # 別的語言java: 參數是個符點數 def hello_world(float b): print("222222") # 別的語言java: 參數是個符點數 def hello_world(float b, float c): print("333333")
反射:了解
hasattr(對象/類,屬性名) -- 對象/類是否有屬性,如果有為True,如果沒有為False
setattr(對象/類,屬性名,屬性值) -- 給對象/類是 添加/修改屬性值.如果屬性存在,則是修改.如果屬性不存在,則是添加.
getattr(對象/類,屬性名) -- 獲取對象/類的屬性值
delattr(對象/類,屬性名) -- 刪除對象/類的屬性和屬性值
class People: def run(self): print("人會跑") p = People() p.hello = "11111" # 添加屬性 print(p.hello) if hasattr(p, "hello"): # 對象/類是否有屬性 print("已存在") else: setattr(p, "hello", "66666") # 給對象/類是 添加/修改屬性值 print(getattr(p, "hello")) # 獲取對象/類的屬性值 # print(p.hello) delattr(p, "hello") # 刪除對象/類的屬性和屬性值 # print(getattr(p, "hello")) # 在獲取 會報錯:AttributeError: 'People' object has no attribute 'hello' if hasattr(People, "kind"): print("已存在") else: setattr(People, "kind", "人類") print(getattr(People, "kind")) # 類訪問kind屬性 print(getattr(p, "kind")) # 對象訪問kind屬性 delattr(People, "kind")
練習題:
1.什么是類?什么是對象?
什么是類?
-
- 類 是對一群具有 相同特征 或者 行為 的事物的一個統稱
- 抽象的
什么是對象?
-
- 對象 是 由類創建出來的一個具體存在
- 具體的
2.類由哪幾部分構成?
- 特征 被稱為 屬性
- 它是什么樣的
- 行為 被稱為 方法
- 它可以做什么
3.列舉幾個生活中類和對象的例子
- 建築物圖紙為類,建造出來的房子為對象
- 狗為類,泰迪為對象
- 測試為類,測試用例為對象
4.類的設計原則
請從類的命名、類中屬性和方法來闡述
- 類名
- 滿足大駝峰命名法
- 分析 整個業務流程,找出其中的 名詞
- 屬性
- 這類事物具有什么樣的特征
- 找名詞
- 方法
- 這類事物具有什么樣的行為
- 找動詞
5.實例方法的特性?__init__方法的作用?
類中實例方法的特性?
-
- 第一個參數一定為self
- 只能被對象調用
- 對象.實例方法,會將對象自身傳給self
__init__方法的作用?
-
- 創建屬性並初始化
- 類名(參數) 會調用__init__(self, 參數)方法
6.實例方法與類方法的區別?
實例方法
- 只能被對象調用
- 第一參數為self,在調用時會自動將對象自身傳給self
- 作用:處理實例屬性
- 在類外
- 對象.實例方法(self, 參數)
- 在類里
- self.實例方法(參數)
類方法
- 能被對象、類來調用
- 需要使用@classmethod裝飾器以及第一個參數為cls
- 在類外
- 對象.類方法(cls, 參數) 會將對象的類傳給cls
- 類.類方法(cls, 參數) 會將類傳給cls
- 在類里
- self.類方法(cls, 參數) 會將對象的類傳給cls
- 類.類方法(cls, 參數) 會將類傳給cls
- 作用:
- 處理類屬性
7.在類的里面和類的外面,調用實例方法、實例屬性、類屬性的方式?
- 參考第6題,或上面總結的6.類的內外部調用
8.__str__實例方法的作用?
- 打印對象時會調用
- 必須return 字符串
9.編寫如下程序,灰色的Tom貓,今年1歲,吃着美味的食物,喝着可口的飲料,非常享受的樣子
- a.根據以上信息,抽象出一個類
- b.定義相關屬性,並能在類的外面調用
- c.定義相關方法,在方法中打印相應信息
class Cat: """ create a cat class """ def __init__(self, name, color, age): """ 構造方法 :param name: 姓名 :param color: 顏色 :param age: 年齡 """ self.name = name self.color = color self.age = age self.status = [] # 狀態 def eat(self): print("{}正在吃東西...".format(self.name)) self.status.append("舔嘴巴") def drink(self): print("{}正在喝飲料...".format(self.name)) self.status.append("喵喵喵...") tom = Cat("Tom", "灰色", 1) print("名字:{}\n顏色:{}\n年齡:{}".format(tom.name, tom.color, tom.age)) tom.eat() tom.drink() print("{}很享受的樣子,{}、{}".format(tom.name, *tom.status))
10.類方法、靜態方法分別是什么?有作用?如何定義?
類方法是什么?
- 針對 類 定義的方法
作用?
- 處理類屬性
如何定義?
@classmethod def 類方法名(cls): pass
- 需要修飾器 @classmethod 來標識
- 第一個參數一般為 cls
- 在類方法內部,可以直接使用 cls 訪問 類屬性 或者 調用類方法
靜態方法是什么? 作用?
- 與對象和類沒有直接關系的一段邏輯
- 但在類中要調用某一個函數,為了類的封裝性,往往會將類外面定義的函數拿到類里面來定義
如何定義?
@staticmethod def 靜態方法名(參數): pass
- 需要修飾器 @staticmethod 來標識
- 在類里面和類外面,都能被對象和類來調用
11.類方法、靜態方法分別如何調用?
答案參考題1
12.什么是繼承?有什么特性?
什么是繼承?
- 獲取已存在類的資源(方法和屬性)
有什么特性?
- 能夠繼承父類的所有方法,私有方法除外
13.編寫如下程序,創建一個名為 Restaurant類,要求至少擁有飯店名和美食種類這兩個特征。
- a.需要創建一個方法來描述飯店名和美食種類相關信息
- b.同時能夠顯示飯店營業狀態(例如:正在營業)
class Restaurant: def __init__(self, name, *args): self.name = name self.args = args def description(self, status): if status == 'OPEN': print('{}飯店營業正常營業'.format(self.name)) for item in self.args: print('美食種類有:{}'.format(item)) elif status == 'CLOSED': print('{}飯店暫停營業,歡迎下次光臨!'.format(self.name)) if __name__ == '__main__': a = Restaurant('金手勺', '米飯', '饅頭', '大餅') a.description('OPEN') a.description('CLOSED')
方式二:
class Restaurant: """ 創建一個餐館類 """ def __init__(self, restaurant_name, cooking_type): self.restaurant_name, self.cooking_type = restaurant_name, cooking_type def describe_restaurant(self): print("*" * 46) print("{:^40s}\n".format(self.restaurant_name)) for key, item in enumerate(self.cooking_type, start=1): print("\t{}.{}".format(key, item)) print("\t請點餐,祝您用餐愉快!") print("*" * 46) def open_restaurant(self): print("{},正在營業...".format(self.restaurant_name)) cooking_types = ["北京烤鴨", "四川麻婆豆腐", "西湖醋魚", "飛龍湯", "無為熏鴨", "東坡肉", "臘味合蒸", "辣子雞", "東安子雞", "清 蒸武昌魚"] famous_restaurant = Restaurant("可優吃不膩餐館", cooking_types) famous_restaurant.describe_restaurant() famous_restaurant.open_restaurant()
14.編寫如下程序,編寫一個數學計算類,要求初始化方法帶參數(傳兩個數字),能夠實現加減乘除運算。
class MathOperation: """ 數學運算類 """ def __init__(self, one_num, two_num): self.first_num, self.second_num = one_num, two_num def add(self): return self.first_num + self.second_num def minus(self): return self.first_num - self.second_num def multiply(self): return self.first_num * self.second_num def divide(self): try: return round(self.first_num / self.second_num, 2) # 相乘之后四舍五入 except ZeroDivisionError: # print("出現除0錯誤!") return "∞" if __name__ == '__main__': # one_number = 10 # two_number = 0 # math_operate = MathOperation(one_number, two_number) # print("{} + {} = {}".format(one_number, two_number, math_operate.add())) # print("{} - {} = {}".format(one_number, two_number, math_operate.minus())) # print("{} * {} = {}".format(one_number, two_number, math_operate.multiply())) # print("{} / {} = {}".format(one_number, two_number, math_operate.divide())) nums = (10, 0) # 傳入兩個參數 math_operate1 = MathOperation(*nums) # *號代表解包:10和0 print("{} + {} = {}".format(*nums, math_operate1.add())) print("{} - {} = {}".format(*nums, math_operate1.minus())) print("{} * {} = {}".format(*nums, math_operate1.multiply())) print("{} / {} = {}".format(*nums, math_operate1.divide()))
15.編寫如下程序,編寫一個工具類和工具箱類,工具需要有的名稱、功能描述、價格,工具箱能夠添加工具、刪除工具、查看工具,並且能獲取工具箱中工具的總數。
class Tool: """ 定義工具類 """ def __init__(self, name, desc, price): """ 構造方法 :param name: 工具名稱 :param desc: 工具描述 :param price: 工具價格 :return: 無 """ self.name, self.desc, self.price = name, desc, price def describe_tool(self): """ 獲取工具描述信息 :return: """ print("\n{:*^100}".format("開始描述")) print(f"名稱:{self.name}\n功能:{self.desc}\n價格: {self.price}") print("{:*^100}\n".format("結束描述")) def __str__(self): return "<{}>".format(self.name) class ToolPackage: """ 定義工具箱類 """ tools_count = 0 def __init__(self, name): self.name = name self.all_tools = [] # 存放工具的列表 def add(self, one_tool): """ 添加工具到工具箱中 :param one_tool: Tool工具對象 :return: """ if isinstance(one_tool, Tool): self.all_tools.append(one_tool) self.modify_tool_count() print("成功添加【{}】到【{}】中!".format(one_tool.name, self.name)) else: print("{}不是工具對象,無法添加!".format(one_tool)) def has_tool(self, one_tool): """ 判斷工具是否在工具箱中 :param one_tool: Tool工具對象或者工具名 :return: True or False """ if isinstance(one_tool, Tool): # 如果one_tool是工具對象 return one_tool in self.all_tools # 判斷是否在工具箱中 elif isinstance(one_tool, str): # 如果是工具名,字符串 for tool_obj in self.all_tools: if one_tool == tool_obj.name: return True return False def remove(self, one_tool): """ 刪除工具 :param one_tool: Tool工具對象或者工具名稱 :return: """ if self.has_tool(one_tool): # 如果要刪除的工具存在 if isinstance(one_tool, Tool): # 如果one_tool為Tool工具對象 self.all_tools.remove(one_tool) else: # 為工具名稱字符串 for index, item in enumerate(self.all_tools): if one_tool == item.name: # 當前遍歷的工具名為 one_tool self.all_tools.pop(index) break # 刪除之后,退出循環 else: print("工具不存在,無法刪除!") def search(self, one_tool): """ 根據工具對象或者工具名稱查找工具 :param one_tool: Tool工具對象或者工具名稱 :return: """ if self.has_tool(one_tool): if isinstance(one_tool, Tool): # 如果one_tool為Tool工具對象 one_tool.describe_tool() else: # 為工具名稱字符串 for index, item in enumerate(self.all_tools): if one_tool == item.name: # 當前遍歷的工具名為 one_tool self.all_tools[index].describe_tool() break # 找到工具之后,退出循環 else: print("工具不存在!") @classmethod def modify_tool_count(cls): """ 類方法,每調用一次工具總數加一 :return: """ cls.tools_count += 1 @classmethod def get_tool_count(cls): """ 類方法,獲取工具箱中,工具總數 :return: """ return cls.tools_count hammer = Tool("錘子", "由金屬或木頭等材料做成的頭和與之垂直的柄構成的敲擊工 具。", 25.2) screwdriver = Tool("螺絲刀", "是一種用來擰轉螺絲以使其就位的工具,通常有一個薄 楔形頭,可插入螺絲釘頭的槽縫或凹口內。", 5) saw = Tool("鋸子", "用來把木料或者其他需要加工的物品鋸斷或鋸割開的工具。", 12) electric_drill = Tool("電鑽", "利用電做動力的鑽孔機具。", 278) family_tool_package = ToolPackage("家用工具箱") # 將工具添加到工具箱中 family_tool_package.add(hammer) family_tool_package.add(screwdriver) # 刪除一個不存在的工具 family_tool_package.remove(saw) # 按照工具的名字來刪除一個工具 family_tool_package.remove("錘子") # 再次添加工具 family_tool_package.add(electric_drill) # 查詢工具 family_tool_package.search(saw) # 查詢不存在的工具 family_tool_package.search(screwdriver) # 查詢已存在的工具 family_tool_package.search("電鑽") # 通過工具名來查詢工具 # 獲取工具總數 print("{}中現在有【{}】件工具。".format(family_tool_package.name, family_tool_package.get_tool_count()))
*******請大家尊重原創,如要轉載,請注明出處:轉載自:https://www.cnblogs.com/shouhu/,謝謝!!*******