python-復盤-面向對象編程

面向對象編程


類和實例

類是創建實例的模板,而實例則是一個一個具體的對象,各個實例擁有的數據都互相獨立,互不影響;

方法就是與實例綁定的函數,和普通函數不同,方法可以直接訪問實例的數據

通過在實例上調用方法,我們就直接操作了對象內部的數據,但無需知道方法內部的實現細節。

和靜態語言不同,Python允許對實例變量綁定任何數據,也就是說,對于兩個實例變量,雖然它們都是同一個類的不同實例,但擁有的變量名稱都可能不同


訪問權限

如果要讓內部屬性不被外部訪問,可以把屬性的名稱前加上兩個下劃線__,在Python中,實例的變量名如果以__開頭,就變成了一個私有變量(private),只有內部可以訪問,外部不能訪問
以之前的Student類,name score 屬性為例:
如果外部代碼要獲取name和score怎么辦?可以給Student類增加get_nameget_score這樣的方法:

class Student(object):
    ...

    def get_name(self):
        return self.__name

    def get_score(self):
        return self.__score

如果又要允許外部代碼修改score怎么辦?可以再給Student類增加set_score方法:

class Student(object):
    ...

    def set_score(self, score):
        self.__score = score

在Python中,變量名類似__xxx__的,也就是以雙下劃線開頭,并且以雙下劃線結尾的,是特殊變量,特殊變量是可以直接訪問的

__xxx 是私有變量,_xxx 是公有變量,但約定俗成,最好當成私有變量,不要隨意訪問


獲取對象信息

type()
isinstance()
用在class判斷繼承關系上方便
dir()
獲得一個對象的所有屬性和方法,可以使用dir()函數,它返回一個包含字符串的list

getattr()

>>> getattr(obj, 'y') # 獲取屬性'y'
19

setattr()

>>> setattr(obj, 'y', 19)    # 設置一個屬性'y'
>>> hasattr(obj, 'y')    # 有屬性'y'嗎?
True

hasattr()

>>> hasattr(obj, 'x')    # 有屬性'x'嗎?
True

通過內置的一系列函數,我們可以對任意一個Python對象進行剖析,拿到其內部的數據。要注意的是,只有在不知道對象信息的時候,我們才會去獲取對象信息。



實例屬性和類屬性

由于Python是動態語言,根據類創建的實例可以任意綁定屬性。

給實例綁定屬性的方法是通過實例變量,或者通過self變量

class Student(object):  #  給實例綁定屬性的方法是通過實例變量,或者通過self變量
    def __init__(self, name,score):
        self.name = name
        self.score = score

s = Student('Bob', 90)    # 這里init定義2個參數,所以這里必須輸入2個參數,否則報錯 
s.name 
# 輸出結果: 'Bob'
s.score 
#  輸出結果:90
In [204]: class Student(object):
     ...:     sex = 'girl'   # 類屬性
     ...:     def __init__(self, name, score):   # 實例屬性
     ...:         self.name = name
     ...:         self.score = score
     ...:

In [205]: s = Student('lily',99)

In [206]: s.name
Out[206]: 'lily'

In [207]: s.score
Out[207]: 99

In [208]: instance = Student()     # 必須傳入2參數
TypeError: __init__() missing 2 required positional arguments: 'name' and 'score'

In [209]: instance = Student('lily',99)
In [210]: instance.sex    # sex是類屬性,但該類的實例同樣可以訪問它
Out[210]: 'girl'

但是,如果Student類本身需要綁定一個屬性呢?可以直接在class中定義屬性,這種屬性是類屬性,歸Student類所有:

class Student(object):    #  類屬性
    name = 'Student'

類屬性雖然歸類所有,但類的所有實例都可以訪問到

>>> class Student(object):
...     name = 'Student'
...
>>> s = Student()   # 創建實例s
>>> print(s.name)   # 打印name屬性,因為實例并沒有name屬性,所以會繼續查找class的name屬性
Student
>>> print(Student.name)   # 打印類的name屬性
Student
>>> s.name = 'Michael'   # 給實例綁定name屬性
>>> print(s.name)   # 由于實例屬性優先級比類屬性高,因此,它會屏蔽掉類的name屬性
Michael
>>> print(Student.name)   # 但是類屬性并未消失,用Student.name仍然可以訪問
Student
>>> del s.name   # 如果刪除實例的name屬性
>>> print(s.name)   # 再次調用s.name,由于實例的name屬性沒有找到,類的name屬性就顯示出來了
Student

??注意:從上面的例子可以看出,在編寫程序的時候,千萬不要把實例屬性和類屬性使用相同的名字,因為相同名稱的實例屬性將屏蔽掉類屬性,但是當你刪除實例屬性后,再使用相同的名稱,訪問到的將是類屬性




對類 子類 繼承 類屬性 類方法 的實驗

class Model(object):
    def __init__(self, high, sex):
        self.high = high
        self.sex = sex

    weight = 100   # 類屬性

    def love(self,x):   # 實例屬性
        print(x, ': i love you~')

class Man(Model):
    def __init__(self, age):
        self.age = age

    state = 'china'   # 類屬性

    def miss(self,y):   # 實例屬性
        print(y, ': i miss you much~')

def what_the_fuck(z):
    print(z.love('kobe'), ':tell me duck type, what the fuck~')


# 測試 Model
test = Model(180, 'male')   # test 為Model類的實例
test1 = Model(high = 180, sex = 'male')   # 在ORM章節,定義有這樣的參數輸入,本質等價
print( test,test1 )   # 結果一樣: <__main__.Model object at 0x1070609b0> #
print( test.high, test.sex )   # 結果: 180 male #
print( Model.weight, test.weight )   # 結果: 100 100  # weight是類屬性,所以類與實例均可調用
print(  test.love('lily')  )  # 結果: lily : i love you~  # 其他方式均報錯

# 測試 Man,繼承自 Model
jack = Man(18)     # 只能輸入一個age參數,父類的 high sex 不影響它
                   #  ??除非用 super()方法去繼承,這樣父類里的__init__(self, *args,**kwargs)才能被繼承作為子類生成實例時必須輸入的參數
print(  jack, jack.age, jack.miss('lily'), jack.love('lily') ) # 運行正常,第一個提示為對象;可識別父類的 love 方法
print( jack.high )  # 報錯,不識別父類的 high
print( jack.state, Man.state, jack.weight, Man.weight )   # 結果 china china 100 100  # 也是就是說子類的類和實例 都 可以繼承父類的類屬性

# 測試鴨子類型
z = Man(18)
print( what_the_fuck(z) )  # 結果: kobe : i love you~ kobe : i love you~  # 這就是鴨子類型,把類實例作為函數的參數,函數中正好有該類實例的自身的函數,可自動識別

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。