[19/10/14-星期一] Python中的對象和類

1、面向對象java

## 什麼是對象?
    - 對象是內存中專門用來存儲數據的一塊區域。
    - 對象中能夠存放各類數據(好比:數字、布爾值、代碼)
    - 對象由三部分組成:
        1.對象的標識(id)
        2.對象的類型(type)
        3.對象的值(value)

## 面向對象(oop)
    - Python是一門面向對象的編程語言
    - 所謂的面向對象的語言,簡單理解就是語言中的全部操做都是經過對象來進行的
    - 面向過程的編程的語言
        - 面向過程指將咱們的程序的邏輯分解爲一個一個的步驟,
            經過對每一個步驟的抽象,來完成程序
        - 例子:
            - 孩子上學
                1.媽媽起牀
                2.媽媽上廁所
                3.媽媽洗漱
                4.媽媽作早飯
                5.媽媽叫孩子起牀
                6.孩子上廁所
                7.孩子要洗漱
                8.孩子吃飯
                9.孩子揹着書包上學校

        - 面向過程的編程思想將一個功能分解爲一個一個小的步驟,
            咱們經過完成一個一個的小的步驟來完成一個程序
        - 這種編程方式,符合咱們人類的思惟,編寫起來相對比較簡單
        - 可是這種方式編寫代碼的每每只適用於一個功能,
            若是要在實現別的功能,即便功能相差極小,也每每要從新編寫代碼,
            因此它可複用性比較低,而且難於維護 

    - 面向對象的編程語言
        - 面向對象的編程語言,關注的是對象,而不關注過程 
        - 對於面向對象的語言來講,一切都是對象       
        - 例子:
            1.孩他媽起牀叫孩子上學

        - 面向對象的編程思想,將全部的功能統一保存到對應的對象中
            好比,媽媽功能保存到媽媽的對象中,孩子的功能保存到孩子對象中
            要使用某個功能,直接找到對應的對象便可
        - 這種方式編寫的代碼,比較容易閱讀,而且比較易於維護,容易複用。
        - 可是這種方式編寫,不太符合常規的思惟,編寫起來稍微麻煩一點 
    
    - 簡單概括一下,面向對象的思想
        1.找對象
        2.搞對象

## 類(class) 
    - 咱們目前所學習的對象都是Python內置的對象
    - 可是內置對象並不能知足全部的需求,因此咱們在開發中常常須要自定義一些對象
    - 類,簡單理解它就至關於一個圖紙。在程序中咱們須要根據類來建立對象
    - 類就是對象的圖紙!
    - 咱們也稱對象是類的實例(instance)
    - 若是多個對象是經過一個類建立的,咱們稱這些對象是一類對象
    - 像 int() float() bool() str() list() dict() .... 這些都是類
    - a = int(10) # 建立一個int類的實例 等價於 a = 10
    - 咱們自定義的類都須要使用大寫字母開頭,使用大駝峯命名法(帕斯卡命名法)來對類命名

    - 類也是一個對象!
    - 類就是一個用來建立對象的對象!
    - 類是type類型的對象,定義類實際上就是定義了一個type類型的對象

## 使用類建立對象的流程(參考圖1)
    1.建立一個變量
    2.在內存中建立一個新對象
    3.將對象的id賦值給變量

## 類的定義(參考圖2)
    - 類和對象都是對現實生活中的事物或程序中的內容的抽象
    - 實際上全部的事物都由兩部分構成:
        1.數據(屬性)
        2.行爲(方法)

    - 在類的代碼塊中,咱們能夠定義變量和函數,
        變量會成爲該類實例的公共屬性,全部的該類實例均可以經過 對象.屬性名 的形式訪問 
        函數會成爲該類實例的公共方法,全部該類實例均可以經過 對象.方法名() 的形式調用方法

    - 注意:
        方法調用時,第一個參數由解析器自動傳遞,因此定義方法時,至少要定義一個形參! 

    - 實例爲何能訪問到類中的屬性和方法
        類中定義的屬性和方法都是公共的,任何該類實例均可以訪問

        - 屬性和方法查找的流程
            當咱們調用一個對象的屬性時,解析器會先在當前對象中尋找是否含有該屬性,
                若是有,則直接返回當前的對象的屬性值,
                若是沒有,則去當前對象的類對象中去尋找,若是有則返回類對象的屬性值,
                若是類對象中依然沒有,則報錯!

        - 類對象和實例對象中均可以保存屬性(方法)
            - 若是這個屬性(方法)是全部的實例共享的,則應該將其保存到類對象中
            - 若是這個屬性(方法)是某個實例獨有,則應該保存到實例對象中     
            
        - 通常狀況下,屬性保存到實例對象中
            而方法須要保存到類對象中    


## 建立對象的流程
    p1 = Person()的運行流程
        1.建立一個變量
        2.在內存中建立一個新對象
        3.__init__(self)方法執行
        4.將對象的id賦值給變量

## 類的基本結構   
    class 類名([父類]) :

        公共的屬性... 

        # 對象的初始化方法
        def __init__(self,...):
            ...

        # 其餘的方法    
        def method_1(self,...):
            ...

        def method_2(self,...):
            ...

        ...    

    - 練習:
        嘗試自定義一個表示狗的類(Dog)      
            屬性:
                name
                age
                gender
                height
                ...
            方法:  
                jiao()
                yao()
                run()
                ...

2、類的簡介編程

a = int(10) # 建立一個int類的實例
b = str('hello') # 建立一個str類的實例

# print(a , type(a))
# print(b , type(b))

# 定義一個簡單的類
# 使用class關鍵字來定義類,語法和函數很像!
# class 類名([父類]):
#   代碼塊
# <class '__main__.MyClass'>
class MyClass():
    pass

# print(MyClass)
# 使用MyClass建立一個對象
# 使用類來建立對象,就像調用一個函數同樣
mc = MyClass() # mc就是經過MyClass建立的對象,mc是MyClass的實例
mc_2 = MyClass()
mc_3 = MyClass()
mc_4 = MyClass()
# mc mc_2 mc_3 mc_4 都是MyClass的實例,他們都是一類對象
# isinstance()用來檢查一個對象是不是一個類的實例
result = isinstance(mc_2,MyClass)
result = isinstance(mc_2,str)

# print(mc , type(mc))
# print('result =',result)

# print(id(MyClass) , type(MyClass))

# 如今咱們經過MyClass這個類建立的對象都是一個空對象
# 也就是對象中實際上什麼都沒有,就至關因而一個空的盒子
# 能夠向對象中添加變量,對象中的變量稱爲屬性
# 語法:對象.屬性名 = 屬性值
mc.name = '孫悟空'
mc_2.name = '豬八戒'

print(mc_2.name)
# 嘗試定義一個表示人的類
class Person :
    # 在類的代碼塊中,咱們能夠定義變量和函數
    # 在類中咱們所定義的變量,將會成爲全部的實例的公共屬性
    # 全部實例均可以訪問這些變量
    name = 'swk' # 公共屬性,全部實例均可以訪問

    # 在類中也能夠定義函數,類中的定義的函數,咱們稱爲方法
    # 這些方法能夠經過該類的全部實例來訪問
    
    def say_hello(self) :
        # 方法每次被調用時,解析器都會自動傳遞第一個實參
        # 第一個參數,就是調用方法的對象自己,
        #   若是是p1調的,則第一個參數就是p1對象
        #   若是是p2調的,則第一個參數就是p2對象
        # 通常咱們都會將這個參數命名爲self

        # say_hello()這個方法,能夠顯示以下格式的數據:
        #   你好!我是 xxx
        #   在方法中不能直接訪問類中的屬性
        print('你好!我是 %s' %self.name)

# 建立Person的實例
p1 = Person()
p2 = Person()

# print(p2.name)

# 調用方法,對象.方法名()
# 方法調用和函數調用的區別
# 若是是函數調用,則調用時傳幾個參數,就會有幾個實參
# 可是若是是方法調用,默認傳遞一個參數,因此方法中至少要定義一個形參


# 修改p1的name屬性
p1.name = '豬八戒'
p2.name = '沙和尚'

p1.say_hello() # '你好!我是 豬八戒'
p2.say_hello() # '你好!我是 沙和尚'

# del p2.name # 刪除p2的name屬性

# print(p1.name) 
# print(p2.name) 
class Person :
    # 在類中能夠定義一些特殊方法(魔術方法)
    # 特殊方法都是以__開頭,__結尾的方法
    # 特殊方法不須要咱們本身調用,不要嘗試去調用特殊方法
    # 特殊方法將會在特殊的時刻自動調用
    # 學習特殊方法:
    #   1.特殊方法何時調用
    #   2.特殊方法有什麼做用
    # 建立對象的流程
    # p1 = Person()的運行流程
    #   1.建立一個變量
    #   2.在內存中建立一個新對象
    #   3.__init__(self)方法執行
    #   4.將對象的id賦值給變量

    # init會在對象建立之後離開執行
    # init能夠用來向新建立的對象中初始化屬性
    # 調用類建立對象時,類後邊的全部參數都會依次傳遞到init()中
    def __init__(self,name):
        # print(self)
        # 經過self向新建的對象中初始化屬性
        self.name = name

    def say_hello(self):
        print('你們好,我是%s'%self.name)


# 目前來說,對於Person類來講name是必須的,而且每個對象中的name屬性基本上都是不一樣
# 而咱們如今是將name屬性在定義爲對象之後,手動添加到對象中,這種方式很容易出現錯誤
# 咱們但願,在建立對象時,必須設置name屬性,若是不設置對象將沒法建立
#   而且屬性的建立應該是自動完成的,而不是在建立對象之後手動完成
# p1 = Person()
# # 手動向對象添加name屬性
# p1.name = '孫悟空'

# p2 = Person()
# p2.name = '豬八戒'

# p3 = Person()
# p3.name = '沙和尚'

# p3.say_hello()

p1 = Person('孫悟空')
p2 = Person('豬八戒')
p3 = Person('沙和尚')
p4 = Person('唐僧')
# p1.__init__() 不要這麼作

# print(p1.name)
# print(p2.name)
# print(p3.name)
# print(p4.name)

p4.say_hello()

練習安全

class Dog:
    '''
        表示狗的類
    '''
    def __init__(self , name , age , gender , height):
        self.name = name
        self.age = age
        self.gender = gender
        self.height = height

    def jiao(self):
        '''
            狗叫的方法
        '''
        print('汪汪汪~~~')

    def yao(self):
        '''
            狗咬的方法
        '''  
        print('我咬你~~')

    def run(self):
        print('%s 快樂的奔跑着~~'%self.name)     


d = Dog('小黑',8,'male',30)

# 目前咱們能夠直接經過 對象.屬性 的方式來修改屬性的值,這種方式致使對象中的屬性能夠隨意修改
#   很是的不安全,值能夠任意修改,不論對錯
# 如今咱們就須要一種方式來加強數據的安全性
#   1.屬性不能隨意修改(我讓你改你才能改,不讓你改你就不能改)
#   2.屬性不能修改成任意的值(年齡不能是負數)
d.name = '阿黃'
d.age = -10
d.run()

print(d.age)

# print(d.name , d.age , d.gender , d.height)
        

 3、封裝編程語言

 

# 封裝是面向對象的三大特性之一
# 封裝指的是隱藏對象中一些不但願被外部所訪問到的屬性或方法
# 如何隱藏一個對象中的屬性?
#   - 將對象的屬性名,修改成一個外部不知道的名字
# 如何獲取(修改)對象中的屬性?
#   - 須要提供一個getter和setter方法使外部能夠訪問到屬性
#   - getter 獲取對象中的指定屬性(get_屬性名)
#   - setter 用來設置對象的指定屬性(set_屬性名)
# 使用封裝,確實增長了類的定義的複雜程度,可是它也確保了數據的安全性
#   1.隱藏了屬性名,使調用者沒法隨意的修改對象中的屬性
#   2.增長了getter和setter方法,很好的控制的屬性是不是隻讀的
#       若是但願屬性是隻讀的,則能夠直接去掉setter方法
#       若是但願屬性不能被外部訪問,則能夠直接去掉getter方法
#   3.使用setter方法設置屬性,能夠增長數據的驗證,確保數據的值是正確的
#   4.使用getter方法獲取屬性,使用setter方法設置屬性
#       能夠在讀取屬性和修改屬性的同時作一些其餘的處理
#   5.使用getter方法能夠表示一些計算的屬性

#java中存在set和get的做用是例如 某些屬性內部私有化外部不能訪問,因此須要set設置get取得屬性
# class Person{  
#    private int age ;               // 聲明年齡屬性

#    public void setage(int age){      // 設置年齡
#         this.age = age ;  
#     }

#     public int getage(){            // 取得年齡
#         return age ;  
#     }

#     public void tell(){  
#        System.out.println( "年齡:" + this.getAge()) ;  
#     }  
# }

# public class Demo{  
#     public static void main(String[] args){  
#         Person per = new Person() ; // 聲明並實例化對象  
#         per.setage(30) ;           // 調用set設置年齡   
#         per.tell() ;                // 輸出信息   
#     }  
# }


class Dog:
    '''
        表示狗的類
    '''
    def __init__(self , name , age):
        self.hidden_name = name
        self.hidden_age = age

    def say_hello(self):
        print('你們好,我是 %s'%self.hidden_name) 

    def get_name(self):
        '''
            get_name()用來獲取對象的name屬性
        '''    
        # print('用戶讀取了屬性')
        return self.hidden_name

    def set_name(self , name):
        # print('用戶修改了屬性')
        self.hidden_name = name

    def get_age(self):
        return self.hidden_age

    def set_age(self , age):
        if age > 0 :#限制設置年齡的條件
            self.hidden_age = age    


d = Dog('旺財',8)

# d.say_hello()

# 調用setter來修改name屬性 
d.set_name('小黑')
d.set_age(-10)

# d.say_hello()
print(d.get_age())
class Rectangle:
    '''一個矩形的類'''
    def __init__ (self,width,height): #注意這裏的下劃線 左邊和右邊是英文狀態下按2次_ 
        self.hidden_width=width
        self.hidden_height=height #初始化構造

    def set_width(self,width):#set get構造
        self.hidden_width=width
    def get_width(self):
        return self.hidden_width

    def set_height(self,height):
        self.hidden_height=height
    def get_height(self):
        return self.hidden_height

    def get_area(self):
        return self.hidden_height*self.hidden_width

r=Rectangle(3,4)
r.set_height(20)
r.set_width(12)

print(r.get_area())
# 能夠爲對象的屬性使用雙下劃線開頭,__xxx  相似於Java中的private修飾符
# 雙下劃線開頭的屬性,是對象的隱藏屬性,隱藏屬性只能在類的內部訪問,沒法經過對象訪問
# 其實隱藏屬性只不過是Python自動爲屬性改了一個名字
#   其實是將名字修改成了,_類名__屬性名 好比 __name -> _Person__name
# class Person:
#     def __init__(self,name):
#         self.__name = name

#     def get_name(self):
#         return self.__name

#     def set_name(self , name):
#         self.__name = name        

# p = Person('孫悟空')

# print(p.__name) __開頭的屬性是隱藏屬性,沒法經過對象訪問
# p.__name = '豬八戒'
# print(p._Person__name)
# p._Person__name = '豬八戒'

# print(p.get_name())

# 使用雙下劃線__開頭的屬性,實際上依然能夠在外部訪問,因此這種方式咱們通常不用
#   通常咱們會將一些私有屬性(不但願被外部訪問的屬性)以_開頭
#   通常狀況下,使用_開頭的屬性都是私有屬性,沒有特殊須要不要修改私有屬性
class Person:
    def __init__(self,name):
        self._name = name  #乾脆hidden也省略了

    def get_name(self):
        return self._name

    def set_name(self , name):
        self._name = name   

p = Person('孫悟空')

print(p._name)
class Person:
    def __init__(self,name,age):
        self._name = name
        self._age = age

    # property(中文意思:屬性)裝飾器,用來將一個get方法,轉換爲對象的屬性
    # 添加爲property裝飾器之後,咱們就能夠像調用屬性同樣使用get方法
    # 使用property裝飾的方法,必須和屬性名是同樣的
    @property    
    def name(self):#相對於get方法 注意名字的變化
        print('get方法執行了~~~')
        return self._name

    # setter方法的裝飾器:@屬性名.setter
    @name.setter    
    def name(self , name): #至關於set方法
        print('setter方法調用了')
        self._name = name        

    @property
    def age(self):
        return self._age

    @age.setter    
    def age(self , age):
        self._age = age   

        

p = Person('豬八戒',18)

p.name = '孫悟空' #像調用屬性的方式去操做方法(函數)
p.age = 28

# 添加爲property裝飾器之後,咱們就能夠像調用屬性同樣使用get方法
print(p.name,p.age) #這裏原本應該寫p.name() 表示調用name方法

4、繼承ide

# 繼承

# 定義一個類 Animal(動物)
#   這個類中須要兩個方法:run() sleep() 
class Animal:
    def run(self):
        print('動物會跑~~~')

    def sleep(self):
        print('動物睡覺~~~')

    # def bark(self):
    #     print('動物嚎叫~~~')   

# 定義一個類 Dog(狗)
#   這個類中須要三個方法:run() sleep() bark()
# class Dog:
#     def run(self):
#         print('狗會跑~~~')

#     def sleep(self):
#         print('狗睡覺~~~')

#     def bark(self):
#         print('汪汪汪~~~') 

# 有一個類,可以實現咱們須要的大部分功能,可是不能實現所有功能
# 如何能讓這個類來實現所有的功能呢?
#   ① 直接修改這個類,在這個類中添加咱們須要的功能
#       - 修改起來會比較麻煩,而且會違反OCP原則
#   ② 直接建立一個新的類
#       - 建立一個新的類比較麻煩,而且須要大量的進行復制粘貼,會出現大量的重複性代碼
#   ③ 直接從Animal類中來繼承它的屬性和方法
#       - 繼承是面向對象三大特性之一
#       - 經過繼承咱們可使一個類獲取到其餘類中的屬性和方法
#       - 在定義類時,能夠在類名後的括號中指定當前類的父類(超類、基類、super)
#           子類(衍生類)能夠直接繼承父類中的全部的屬性和方法
#           
#  經過繼承能夠直接讓子類獲取到父類的方法或屬性,避免編寫重複性的代碼,而且也符合OCP原則
#   因此咱們常常須要經過繼承來對一個類進行擴展

class Dog(Animal):
    def bark(self):
        print('汪汪汪~~~') 

    def run(self):
        print('狗跑~~~~')    

class Hashiqi(Dog):
    def fan_sha(self):
        print('我是一隻傻傻的哈士奇')        

d = Dog()
h = Hashiqi()

# d.run()
# d.sleep()
# d.bark()

# r = isinstance(d , Dog)
# r = isinstance(d , Animal)
# print(r)

# 在建立類時,若是省略了父類,則默認父類爲object
#   object是全部類的父類,全部類都繼承自object
class Person(object):
    pass

# issubclass() 檢查一個類是不是另外一個類的子類
# print(issubclass(Animal , Dog))
# print(issubclass(Animal , object))
# print(issubclass(Person , object))

# isinstance()用來檢查一個對象是不是一個類的實例
#   若是這個類是這個對象的父類,也會返回True
#   全部的對象都是object的實例
print(isinstance(print , object))

重寫函數

# 繼承

# 定義一個類 Animal(動物)
#   這個類中須要兩個方法:run() sleep() 
class Animal:
    def run(self):
        print('動物會跑~~~')

    def sleep(self):
        print('動物睡覺~~~')


class Dog(Animal):
    def bark(self):
        print('汪汪汪~~~') 

    def run(self):
        print('狗跑~~~~')    


# 若是在子類中若是有和父類同名的方法,則經過子類實例去調用方法時,
#   會調用子類的方法而不是父類的方法,這個特色咱們成爲叫作方法的重寫(覆蓋,override)
# 建立Dog類的實例
# d = Dog()

# d.run()

# 當咱們調用一個對象的方法時,
#   會優先去當前對象中尋找是否具備該方法,若是有則直接調用
#   若是沒有,則去當前對象的父類中尋找,若是父類中有則直接調用父類中的方法,
#   若是沒有,則去父類的父類中尋找,以此類推,直到找到object,若是依然沒有找到,則報錯
class A(object):
    def test(self):
        print('AAA')

class B(A):
    def test(self):
        print('BBB')

class C(B):
    def test(self):
        print('CCC')   

# 建立一個c的實例
c = C()
c.test()
class Animal:
    def __init__(self,name):
        self._name = name

    def run(self):
        print('動物會跑~~~')

    def sleep(self):
        print('動物睡覺~~~')

    @property
    def name(self):
        return self._name

    @name.setter    
    def name(self,name):
        self._name = name

# 父類中的全部方法都會被子類繼承,包括特殊方法,也能夠重寫特殊方法
class Dog(Animal):

    def __init__(self,name,age):
        # 但願能夠直接調用父類的__init__來初始化父類中定義的屬性
        # super() 能夠用來獲取當前類的父類,
        #   而且經過super()返回對象調用父類方法時,不須要傳遞self
        super().__init__(name)
        self._age = age

    def bark(self):
        print('汪汪汪~~~') 

    def run(self):
        print('狗跑~~~~')   

    @property
    def age(self):
        return self._age

    @age.setter    
    def age(self,age):
        self._age = age        


d = Dog('旺財',18) 

print(d.name)       
print(d.age)       

class A(object):
    def test(self):
        print('AAA')

class B(object):
    def test(self):
        print('B中的test()方法~~')

    def test2(self):
        print('BBB') 

# 在Python中是支持多重繼承的,也就是咱們能夠爲一個類同時指定多個父類
#   能夠在類名的()後邊添加多個類,來實現多重繼承
#   多重繼承,會使子類同時擁有多個父類,而且會獲取到全部父類中的方法
# 在開發中沒有特殊的狀況,應該儘可能避免使用多重繼承,由於多重繼承會讓咱們的代碼過於複雜
# 若是多個父類中有同名的方法,則會如今第一個父類中尋找,而後找第二個,而後找第三個。。。
#   前邊父類的方法會覆蓋後邊父類的方法,乾爹不如親爹
class C(A,B):#一個兒子多個爸爸,Java中就不行
    pass

# 類名.__bases__ 這個屬性能夠用來獲取當前類的全部父類    
# print(C.__bases__) (<class '__main__.B'>,)
# print(B.__bases__) (<class 'object'>,)

# print(C.__bases__) # (<class '__main__.A'>, <class '__main__.B'>)

c = C()

c.test()

 多態工具

# 多態是面向對象的三大特徵之一
# 多態從字面上理解是多種形態
# 狗(狼狗、藏獒、哈士奇、古牧 。。。)
# 一個對象能夠以不一樣的形態去呈現

# 定義兩個類
class A:
    def __init__(self,name):
        self._name = name

    @property
    def name(self):
        return self._name
        
    @name.setter
    def name(self,name):
        self._name = name   

class B:
    def __init__(self,name):
        self._name = name

    def __len__(self):
        return 10

    @property
    def name(self):
        return self._name
        
    @name.setter
    def name(self,name):
        self._name = name   

class C:
    pass


a = A('孫悟空')
b = B('豬八戒')
c = C()

# 定義一個函數
# 對於say_hello()這個函數來講,只要對象中含有name屬性,它就能夠做爲參數傳遞
#   這個函數並不會考慮對象的類型,只要有name屬性便可
def say_hello(obj):
    print('你好 %s'%obj.name)

# 在say_hello_2中咱們作了一個類型檢查,也就是隻有obj是A類型的對象時,才能夠正常使用,
#   其餘類型的對象都沒法使用該函數,這個函數就違反了多態
# 違反了多態的函數,只適用於一種類型的對象,沒法處理其餘類型對象,這樣致使函數的適應性很是的差
# 注意,向isinstance()這種函數,在開發中通常是不會使用的!
def say_hello_2(obj):
    # 作類型檢查
    if isinstance(obj , A):
        print('你好 %s'%obj.name)    
# say_hello(b)    
# say_hello_2(b)

# 鴨子類型
# 若是一個東西,走路像鴨子,叫聲像鴨子,那麼它就是鴨子

# len()
# 之因此一個對象能經過len()來獲取長度,是由於對象中具備一個特殊方法__len__
# 換句話說,只要對象中具備__len__特殊方法,就能夠經過len()來獲取它的長度
l = [1,2,3]
s = 'hello'

# print(len(l))
# print(len(s))
print(len(b))
print(len(c))

# 面向對象的三大特徵:
#   封裝
#       - 確保對象中的數據安全
#   繼承
#       - 保證了對象的可擴展性
#   多態
#       - 保證了程序的靈活性

5、總結屬性和方法oop

# 定義一個類
class A(object):

    # 類屬性
    # 實例屬性
    # 類方法
    # 實例方法
    # 靜態方法

    # 類屬性,直接在類中定義的屬性是類屬性
    #   類屬性能夠經過類或類的實例訪問到
    #   可是類屬性只能經過類對象來修改,沒法經過實例對象修改
    count = 0

    def __init__(self):
        # 實例屬性,經過實例對象添加的屬性屬於實例屬性
        #   實例屬性只能經過實例對象來訪問和修改,類對象沒法訪問修改
        self.name = '孫悟空'

    # 實例方法
    #   在類中定義,以self爲第一個參數的方法都是實例方法
    #   實例方法在調用時,Python會將調用對象做爲self傳入  
    #   實例方法能夠經過實例和類去調用
    #       當經過實例調用時,會自動將當前調用對象做爲self傳入
    #       當經過類調用時,不會自動傳遞self,此時咱們必須手動傳遞self
    def test(self):
        print('這是test方法~~~ ' , self)    

    # 類方法    
    # 在類內部使用 @classmethod 來修飾的方法屬於類方法
    # 類方法的第一個參數是cls,也會被自動傳遞,cls就是當前的類對象
    #   類方法和實例方法的區別,實例方法的第一個參數是self,而類方法的第一個參數是cls
    #   類方法能夠經過類去調用,也能夠經過實例調用,沒有區別
    @classmethod
    def test_2(cls):
        print('這是test_2方法,他是一個類方法~~~ ',cls)
        print(cls.count)

    # 靜態方法
    # 在類中使用 @staticmethod 來修飾的方法屬於靜態方法  
    # 靜態方法不須要指定任何的默認參數,靜態方法能夠經過類和實例去調用  
    # 靜態方法,基本上是一個和當前類無關的方法,它只是一個保存到當前類中的函數
    # 靜態方法通常都是一些工具方法,和當前類無關
    @staticmethod
    def test_3():
        print('test_3執行了~~~')


a = A()
# 實例屬性,經過實例對象添加的屬性屬於實例屬性
# a.count = 10
# A.count = 100
# print('A ,',A.count) 
# print('a ,',a.count) 
# print('A ,',A.name) 
# print('a ,',a.name)   

# a.test() 等價於 A.test(a)

# A.test_2() 等價於 a.test_2()

A.test_3()
a.test_3()

6、垃圾回收性能

# 就像咱們生活中會產生垃圾同樣,程序在運行過程中也會產生垃圾
# 程序運行過程當中產生的垃圾會影響到程序的運行的運行性能,因此這些垃圾必須被及時清理
# 沒用的東西就是垃圾
# 在程序中沒有被引用的對象就是垃圾,這種垃圾對象過多之後會影響到程序的運行的性能
#   因此咱們必須進行及時的垃圾回收,所謂的垃圾回收就是講垃圾對象從內存中刪除
# 在Python中有自動的垃圾回收機制,它會自動將這些沒有被引用的對象刪除,
#   因此咱們不用手動處理垃圾回收

class A:
    def __init__(self):
        self.name = 'A類'

    # del是一個特殊方法,它會在對象被垃圾回收前調用
    def __del__(self):
        print('A()對象被刪除了~~~',self)

a = A()
b = a # 又使用一個變量b,來引用a對應的對象

print(a.name)

# a = None # 將a設置爲了None,此時沒有任何的變量對A()對象進行引用,它就是變成了垃圾
# b = None
# del a
# del b
input('回車鍵退出...')
# 特殊方法,也稱爲魔術方法
# 特殊方法都是使用雙下劃線__開頭和結尾的
# 特殊方法通常不須要咱們手動調用,須要在一些特殊狀況下自動執行

# 定義一個Person類
class Person(object):
    """人類"""
    def __init__(self, name , age):
        self.name = name
        self.age = age

    # __str__()這個特殊方法會在嘗試將對象轉換爲字符串的時候調用
    # 它的做用能夠用來指定對象轉換爲字符串的結果  (print函數)  
    def __str__(self):
        return 'Person [name=%s , age=%d]'%(self.name,self.age)        

    # __repr__()這個特殊方法會在對當前對象使用repr()函數時調用
    # 它的做用是指定對象在 ‘交互模式’中直接輸出的效果    
    def __repr__(self):
        return 'Hello'        

    # object.__add__(self, other)
    # object.__sub__(self, other)
    # object.__mul__(self, other)
    # object.__matmul__(self, other)
    # object.__truediv__(self, other)
    # object.__floordiv__(self, other)
    # object.__mod__(self, other)
    # object.__divmod__(self, other)
    # object.__pow__(self, other[, modulo])
    # object.__lshift__(self, other)
    # object.__rshift__(self, other)
    # object.__and__(self, other)
    # object.__xor__(self, other)
    # object.__or__(self, other)

    # object.__lt__(self, other) 小於 <
    # object.__le__(self, other) 小於等於 <=
    # object.__eq__(self, other) 等於 ==
    # object.__ne__(self, other) 不等於 !=
    # object.__gt__(self, other) 大於 >
    # object.__ge__(self, other) 大於等於 >= 
    
    # __len__()獲取對象的長度

    # object.__bool__(self)
    # 能夠經過bool來指定對象轉換爲布爾值的狀況
    def __bool__(self):
        return self.age > 17

    # __gt__會在對象作大於比較的時候調用,該方法的返回值將會做爲比較的結果
    # 他須要兩個參數,一個self表示當前對象,other表示和當前對象比較的對象
    # self > other
    def __gt__(self , other):
        return self.age > other.age


# 建立兩個Person類的實例        
p1 = Person('孫悟空',18)
p2 = Person('豬八戒',28)

# 打印p1
# 當咱們打印一個對象時,實際上打印的是對象的中特殊方法 __str__()的返回值
# print(p1) # <__main__.Person object at 0x04E95090>
# print(p1)
# print(p2)

# print(repr(p1))

# t = 1,2,3
# print(t) # (1, 2, 3)

# print(p1 > p2)
# print(p2 > p1)

# print(bool(p1))

# if p1 :
#     print(p1.name,'已經成年了')
# else :
#     print(p1.name,'還未成年了')
相關文章
相關標籤/搜索