一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

從零學Python:17課-面向?qū)ο缶幊蹋ㄟM階)

 千鋒Python學堂 2020-07-28

上一節(jié)課我們講解了Python面向?qū)ο缶幊痰幕A(chǔ)入門知識,這一節(jié)課我們繼續(xù)來討論面向?qū)ο缶幊滔嚓P(guān)的內(nèi)容。

另外上節(jié)課很多伙伴要了視頻學習教程,提醒大家哈,認真的看完,不清楚的地方,可以再說!

可見性和屬性裝飾器

在很多面向?qū)ο缶幊陶Z言中,對象的屬性通常會被設(shè)置為私有(private)或受保護(protected)的成員,簡單的說就是不允許直接訪問這些屬性;對象的方法通常都是公開的(public),因為公開的方法是對象能夠接受的消息,也是對象暴露給外界的調(diào)用接口,這就是所謂的訪問可見性。在Python中,可以通過給對象屬性名添加前綴下劃線的方式來說明屬性的訪問可見性,例如,可以用__name表示一個私有屬性,_name表示一個受保護屬性,代碼如下所示。

class Student:

def __init__(self, name, age):
self.__name = name
self.__age = age

def study(self, course_name):
print(f'{self.__name}正在學習{course_name}.')


stu = Student('王大錘', 20)
stu.study('Python程序設(shè)計')
print(stu.__name)

上面代碼的最后一行會引發(fā)AttributeError(屬性錯誤)異常,異常消息為:'Student' object has no attribute '__name'。由此可見,以__開頭的屬性__name是私有的,在類的外面無法直接訪問,但是類里面的study方法中可以通過self.__name訪問該屬性。

需要提醒大家的是,Python并沒有從語法上嚴格保證私有屬性的私密性,它只是給私有的屬性和方法換了一個名字來阻撓對它們的訪問,事實上如果你知道更換名字的規(guī)則仍然可以訪問到它們,我們可以對上面的代碼稍作修改就可以訪問到私有的。

class Student:

def __init__(self, name, age):
self.__name = name
self.__age = age

def study(self, course_name):
print(f'{self.__name}正在學習{course_name}.')


stu = Student('王大錘', 20)
stu.study('Python程序設(shè)計')
print(stu._Student__name, stu._Student__age)

Python中做出這樣的設(shè)定是基于一句名言:“We are all consenting adults here”(大家都是成年人)。Python語言的設(shè)計者認為程序員要為自己的行為負責,而不是由Python語言本身來嚴格限制訪問可見性,而大多數(shù)的程序員都認為開放比封閉要好,把對象的屬性私有化并不是必須的東西。

Python中可以通過property裝飾器為“私有”屬性提供讀取和修改的方法,裝飾器通常會放在類、函數(shù)或方法的聲明之前,通過一個@符號表示將裝飾器應(yīng)用于類、函數(shù)或方法。裝飾器的概念我們會在稍后的課程中以專題的形式為大家講解,這里我們只需要了解property裝飾器的用法就可以了。

class Student:

def __init__(self, name, age):
self.__name = name
self.__age = age

# 屬性訪問器(getter方法) - 獲取__name屬性
@property
def name(self):
return self.__name

# 屬性修改器(setter方法) - 修改__name屬性
@name.setter
def name(self, name):
# 如果name參數(shù)不為空就賦值給對象的__name屬性
# 否則將__name屬性賦值為'無名氏',有兩種寫法
# self.__name = name if name else '無名氏'
self.__name = name or '無名氏'

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


stu = Student('王大錘', 20)
print(stu.name, stu.age) # 王大錘 20
stu.name = ''
print(stu.name) # 無名氏
# stu.age = 30 # AttributeError: can't set attribute

在實際項目開發(fā)中,我們并不經(jīng)常使用私有屬性,屬性裝飾器的使用也比較少,所以上面的知識點大家簡單了解一下就可以了。

動態(tài)屬性

Python是一門動態(tài)語言,維基百科對動態(tài)語言的解釋是:“在運行時可以改變其結(jié)構(gòu)的語言,例如新的函數(shù)、對象、甚至代碼可以被引進,已有的函數(shù)可以被刪除或是其他結(jié)構(gòu)上的變化。動態(tài)語言非常靈活,目前流行的Python和JavaScript都是動態(tài)語言,除此之外如PHP、Ruby等也都屬于動態(tài)語言,而C、C++等語言則不屬于動態(tài)語言”。

在Python中,我們可以動態(tài)為對象添加屬性,這是Python作為動態(tài)類型語言的一項特權(quán),代碼如下所示。需要提醒大家的是,對象的方法其實本質(zhì)上也是對象的屬性,如果給對象發(fā)送一個無法接收的消息,引發(fā)的異常仍然是AttributeError。

class Student:

def __init__(self, name, age):
self.name = name
self.age = age


stu = Student('王大錘', 20)
# 為Student對象動態(tài)添加sex屬性
stu.sex = '男'

如果不希望在使用對象時動態(tài)的為對象添加屬性,可以使用Python的__slots__魔法。對于Student類來說,可以在類中指定__slots__ = ('name', 'age'),這樣Student類的對象只能有name和age屬性,如果想動態(tài)添加其他屬性將會引發(fā)異常,代碼如下所示。

class Student:
__slots__ = ('name', 'age')

def __init__(self, name, age):
self.name = name
self.age = age


stu = Student('王大錘', 20)
# AttributeError: 'Student' object has no attribute 'sex'
stu.sex = '男'

靜態(tài)方法和類方法

之前我們在類中定義的方法都是對象方法,換句話說這些方法都是對象可以接收的消息。除了對象方法之外,類中還可以有靜態(tài)方法和類方法,這兩類方法是發(fā)給類的消息,二者并沒有實質(zhì)性的區(qū)別。在面向?qū)ο蟮氖澜缋铮磺薪詾閷ο?,我們定義的每一個類其實也是一個對象,而靜態(tài)方法和類方法就是發(fā)送給類對象的消息。那么,什么樣的消息會直接發(fā)送給類對象呢?

舉一個例子,定義一個三角形類,通過傳入三條邊的長度來構(gòu)造三角形,并提供計算周長和面積的方法。計算周長和面積肯定是三角形對象的方法,這一點毫無疑問。但是在創(chuàng)建三角形對象時,傳入的三條邊長未必能構(gòu)造出三角形,為此我們可以先寫一個方法來驗證給定的三條邊長是否可以構(gòu)成三角形,這種方法很顯然就不是對象方法,因為在調(diào)用這個方法時三角形對象還沒有創(chuàng)建出來。我們可以把這類方法設(shè)計為靜態(tài)方法或類方法,也就是說這類方法不是發(fā)送給三角形對象的消息,而是發(fā)送給三角形類的消息,代碼如下所示。

class Triangle(object):
"""三角形類"""

def __init__(self, a, b, c):
"""初始化方法"""
self.a = a
self.b = b
self.c = c

@staticmethod
def is_valid(a, b, c):
"""判斷三條邊長能否構(gòu)成三角形(靜態(tài)方法)"""
return a + b > c and b + c > a and a + c > b

# @classmethod
# def is_valid(cls, a, b, c):
# """判斷三條邊長能否構(gòu)成三角形(類方法)"""
# return a + b > c and b + c > a and a + c > b

def perimeter(self):
"""計算周長"""
return self.a + self.b + self.c

def area(self):
"""計算面積"""
p = self.perimeter() / 2
return (p * (p - self.a) * (p - self.b) * (p - self.c)) ** 0.5

上面的代碼使用staticmethod裝飾器聲明了is_valid方法是Triangle類的靜態(tài)方法,如果要聲明類方法,可以使用classmethod裝飾器。可以直接使用類名.方法名的方式來調(diào)用靜態(tài)方法和類方法,二者的區(qū)別在于,類方法的第一個參數(shù)是類對象本身,而靜態(tài)方法則沒有這個參數(shù)。簡單的總結(jié)一下,對象方法、類方法、靜態(tài)方法都可以通過類名.方法名的方式來調(diào)用,區(qū)別在于方法的第一個參數(shù)到底是普通對象還是類對象,還是沒有接受消息的對象。靜態(tài)方法通常也可以直接寫成一個獨立的函數(shù),因為它并沒有跟特定的對象綁定。

從零學Python:17課-面向?qū)ο缶幊蹋ㄟM階)

繼承和多態(tài)

面向?qū)ο蟮木幊陶Z言支持在已有類的基礎(chǔ)上創(chuàng)建新類,從而減少重復代碼的編寫。提供繼承信息的類叫做父類(超類、基類),得到繼承信息的類叫做子類(派生類、衍生類)。例如,我們定義一個學生類和一個老師類,我們會發(fā)現(xiàn)他們有大量的重復代碼,而這些重復代碼都是老師和學生作為人的公共屬性和行為,所以在這種情況下,我們應(yīng)該先定義人類,再通過繼承,從人類派生出老師類和學生類,代碼如下所示。

class Person:
"""人類"""

def __init__(self, name, age):
self.name = name
self.age = age

def eat(self):
print(f'{self.name}正在吃飯.')

def sleep(self):
print(f'{self.name}正在睡覺.')


class Student(Person):
"""學生類"""

def __init__(self, name, age):
# super(Student, self).__init__(name, age)
super().__init__(name, age)

def study(self, course_name):
print(f'{self.name}正在學習{course_name}.')


class Teacher(Person):
"""老師類"""

def __init__(self, name, age, title):
# super(Teacher, self).__init__(name, age)
super().__init__(name, age)
self.title = title

def teach(self, course_name):
print(f'{self.name}{self.title}正在講授{course_name}.')



stu1 = Student('白元芳', 21)
stu2 = Student('狄仁杰', 22)
teacher = Teacher('武則天', 35, '副教授')
stu1.eat()
stu2.sleep()
teacher.teach('Python程序設(shè)計')
stu1.study('Python程序設(shè)計')

繼承的語法是在定義類的時候,在類名后的圓括號中指定當前類的父類。Python語言允許多重繼承,也就是說一個類可以有一個或多個父類,關(guān)于多重繼承的問題我們在后面會有更為詳細的討論。在子類的初始化方法中,我們可以通過super().__init__()來調(diào)用父類初始化方法,super函數(shù)是Python內(nèi)置函數(shù)中專門為獲取當前對象的父類對象而設(shè)計的。從上面的代碼可以看出,子類除了可以通過繼承得到父類提供的屬性和方法外,還可以定義自己特有的屬性和方法,所以子類比父類擁有的更多的能力。在實際開發(fā)中,我們經(jīng)常會用子類對象去替換掉一個父類對象,這是面向?qū)ο缶幊讨幸粋€常見的行為,也叫做“里氏替換原則”(Liskov Substitution Principle)。

子類繼承父類的方法后,還可以對方法進行重寫(重新實現(xiàn)該方法),不同的子類可以對父類的同一個方法給出不同的實現(xiàn)版本,這樣的方法在程序運行時就會表現(xiàn)出多態(tài)行為(調(diào)用相同的方法,做了不同的事情)。多態(tài)是面向?qū)ο缶幊讨凶罹璧牟糠?,當然也是對初學者來說最難以理解和靈活運用的部分,我們會在下一節(jié)課中用專門的例子來講解多態(tài)這個知識點。

簡單的總結(jié)

Python是動態(tài)語言,Python中的對象可以動態(tài)的添加屬性。在面向?qū)ο蟮氖澜缰校?span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;margin: 0px;padding: 0px;border: 0px;">一切皆為對象,我們定義的類也是對象,所以類也可以接收消息,對應(yīng)的方法是類方法或靜態(tài)方法。通過繼承,我們可以從已有的類創(chuàng)建新類,實現(xiàn)對已有類代碼的復用。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    欧美日韩国产成人高潮| 日本欧美三级中文字幕| 日韩中文字幕在线不卡一区| 日本高清视频在线播放| 91欧美日韩精品在线| 日韩亚洲激情在线观看| 又黄又色又爽又免费的视频| 国产三级不卡在线观看视频| 91日韩在线观看你懂的| 国产激情国产精品久久源| 国产又粗又猛又爽色噜噜| 国内精品偷拍视频久久| 亚洲av成人一区二区三区在线| 国产一区二区三区免费福利 | 亚洲黄香蕉视频免费看| 久久热这里只有精品视频| 黄片美女在线免费观看| 欧美精品日韩精品一区| 青青免费操手机在线视频| 久久精品欧美一区二区三不卡| 九九热国产这里只有精品| 亚洲一区二区三区三区| 国产亚洲欧美另类久久久| 国产日本欧美特黄在线观看| 国产亚洲视频香蕉一区| 国产精品视频一区二区秋霞| 国产一区麻豆水好多高潮| 精品丝袜一区二区三区性色| 麻豆精品在线一区二区三区| 天海翼高清二区三区在线| 国产一区日韩二区欧美| 国产精品美女午夜视频| 亚洲欧美日本国产有色| 欧美韩日在线观看一区| 九九热视频免费在线视频| 六月丁香六月综合缴情| 国产麻豆一区二区三区在| 日韩人妻一区中文字幕| a久久天堂国产毛片精品| 91麻豆精品欧美视频| 99久久国产精品成人观看|