9 - Python 類與對象


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/,謝謝!!******* 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM