原創:叫我詹躲躲
來源:思否
鏈接:python面型對象編程進階(繼承、多態、私有化、異常捕獲、類屬性和類方法)
致謝:感謝求知教育提供的視頻教程
1.單繼承
## 封裝,繼承和多態
## 1.封裝
1、滿足把內容封裝到某個地方,另一個地方去調用封裝的內容
2、使用初始化構造方法,或者使用self獲取封裝的內容
## 2.繼承
子類繼承父類的屬性和內容
1.1單繼承示例
class Animal:
def eat(self):
print('吃飯了')
pass
def drink(self):
print('喝水了')
pass
class Dog(Animal):
def wwj(self):
## 子類獨有的實現
print('小狗汪汪叫')
pass
class Cat(Animal):
def mmj(self):
## 子類獨有的實現
print('小貓喵喵叫')
pass
d1 = Dog()
d1.eat()
d2 = Cat()
d2.eat()
## 總結:所以對於面向對象的繼承來説,可以極大的提升效率,減少重複代碼
2.多繼承
class Shenxian:
def fly(self):
print('神仙會飛')
pass
class Monkey:
def chitao(self):
print('猴子喜歡吃桃')
pass
class Sunwukong(Shenxian,Monkey):
pass
swk = Sunwukong()
swk.fly()
swk.chitao()
2.1 注意方法重名:
## 多個父類存在相同的方法,該調用哪一個
class D(object):
def eat(self):
print('D.eat')
pass
class C(object):
def eat(self):
print('C.eat')
pass
class B(D):
pass
class A(B,C):
pass
a = A()
a.eat
print(A.__mro__) ##顯示類的繼承順序
<class '__main__.A'>,
<class '__main__.B'>,
<class '__main__.D'>,
<class '__main__.C'>,
<class 'object'>
## 執行順序應該是 去A裏面查找,找第一個父類,A中沒有的話,去B中查找,,B類中沒有,C類中沒有,去D類中查找;
2.2案例 簡潔繼承
class Grandfather():
def eat(self):
print('吃的方法')
pass
pass
class Father(Grandfather):
pass
class Son(Father):
pass
son = Son()
print(Son.__mro__)
## <class '__main__.Son'>,
## <class '__main__.Father'>,
## <class '__main__.Grandfather'>,
## <class 'object'>
2.3重寫父類方法
class Grandfather():
def eat(self):
print('吃的方法')
pass
pass
class Father(Grandfather):
## 覆蓋了父類的方法
def eat(self):
print('爸爸經常吃海鮮')
pass
class Son(Father):
pass
son = Son()
print(Son.__mro__)
## 定義跟父類相同的方法,可以實現覆蓋和重寫父類的方法
2.4重寫初始化方法
class Grandfather():
def __init__(self,name):
self.name = name
pass
def eat(self):
print('吃的方法')
pass
pass
class Father(Grandfather):
def __init__(self):
pass
## 覆蓋了父類的方法
def eat(self):
print('爸爸經常吃海鮮')
pass
class Son(Father):
pass
son = Son()
print(Son.__mro__)
2.5調用父類初始化方法
class Father:
def __init__(self,name):
self.name = name
pass
## 覆蓋了父類的方法
def eat(self):
print('爸爸經常吃海鮮')
pass
class Son(Father):
def __init__(self,name):
Father.__init__(self,name) ##調用父類的方法,可以具備name屬性
## 或者
## super.__init__(name) ##也可以這樣寫
self.age = 90 ## 添加新的實例方法
self.sex = '男'
pass
pass
son = Son('hello')
2.6 調用父類的方法
class Father:
def __init__(self,name):
self.name = name
pass
## 覆蓋了父類的方法
def eat(self):
print('父類的吃方法')
pass
class Son(Father):
def __init__(self,name):
Father.__init__(self,name) ##調用父類的方法,可以具備name屬性
## 或者
## super.__init__(name) ##也可以這樣寫
self.age = 90 ## 添加新的實例方法
self.sex = '男'
pass
pass
def __str__(self):
print('{}'.format(self.name))
pass
def eat(self):
super().eat() ##調用父類的方法
print('子類的吃方法')
pass
son = Son('詹躲躲')
son.eat()
## 父類的吃方法
## 子類的吃方法
3 多態
同一種行為,對於不同子類【對象】有不同的實現方式
3.1 要想實現多態,必須有兩個前提
1.繼承:發生在父類和子類之間2.重寫:子類重寫父類的方法
3.1 案例演示
class Animal:
## 基本類
def say(self):
print('動物類')
pass
pass
class Duck(Animal):
## 子類 派生類
def say(self):
print('鴨子類')
pass
pass
class Dog(Animal):
## 子類 派生類
def say(self):
print('小狗類')
pass
pass
## duck1 = Duck()
## duck1.say()
## dog = Dog()
## dog.say()
def commonIvoke(obj):
## 統一調用
obj.say()
## 循環統一調用
listObj = [Duck(),Dog()]
for item in listObj:
commonIvoke(item)
## 在定義時的類型跟調用時不一樣的時候,稱為多態。
3.2 多態的好處
1.增加程序的靈活性
2.增加程序的擴展性
4.類屬性和實例屬性
## 類屬性:就是類對象擁有的屬性,它被所有類對象的實例對象所共有,類對象和實例對象可以訪問。
## 實例屬性:實例對象所擁有的屬性,只能通過實例對象訪問。
class Student:
## 類屬性
name = '叫我詹躲躲'
def __init__(self,age):
self.age = age
pass
pass
lm = Student(18)
## 通過實例對象去訪問類屬性
print(lm.name)
print(lm.age)
## 通過類對象去訪問
print(Student.name)
print(Student.age)
## 總結
## 類屬性:類對象和實例對象都可以訪問
## 實例屬性:只能由實例屬性訪問
## 所有的實例對象指向同一類對象
## 實例對象去修改類屬性 不能修改
## 類對象可以修改類屬性 可以修改
5.類屬性和靜態方法
## 裝飾器@classmethod
class Person:
country = 'china'
## 類方法 用classmethod修飾
@classmethod
def get_country(cls):
return cls.country ## 訪問類屬性
pass
@classmethod
def change_country(cls):
cls.country = 'America'
pass
## 通過類對象去引用
print(Person.get_country())
print(Person.change_country())
print(Person.get_country())
5.1 靜態方法
class Person:
country = 'china'
## 類方法 用classmethod修飾
@classmethod
def get_country(cls):
return cls.country ## 訪問類屬性
pass
@classmethod
def change_country(cls):
cls.country = 'America'
pass
@staticmethod
def get_data():
return Person.country
pass
## 通過類對象去引用
print(Person.get_country())
print(Person.change_country())
print(Person.get_country())
print(Person.get_data())
一般不會通過是實例對象去訪問靜態方法
由於靜態方法主要存放邏輯方法,本身與類以及實例沒有交互,也就是不會涉及類中方法和屬性的操作
根據資源能夠有效的利用
5.2求系統當前的時間
import time
class sys_time:
def __init__(self,hour,min,second):
self.hour = hour
self.min =min
self.second = second
@staticmethod
## 獨立的功能
def show_time():
return time.strftime('%H:%M:%S',time.localtime())
print(sys_time.show_time())
## 15:15:44
5.3 總結
1.類方法的第一個參數是類對象,cls進而去引用類對象的屬性和方法
2.實例方法的第一個參數是實例屬性,若存在相同的實例屬性或者方法,實例屬性優先級最高
3.靜態方法不需要額外的參數,若需要引用屬性。,則可以通過類對象或者實例對象去引用即可,必須使用裝飾器@staticmethod裝飾
6.私有化
6.1 私有化屬性
## 私有屬性 以__開頭,聲明為屬性私有,不能在類的外部被使用或者直接訪問。
class Person(object):
def __init__(self):
self.__name = '叫我詹躲躲' ## 私有化
self.age = '21'
pass
def __str__(self):
return '{}的年齡是{}'.format(self.__name,self.age)
person = Person()
## print(person.__name) ##報錯
print(person) ##可以訪問
## 叫我詹躲躲的年齡是21
## 私有屬性,不能被子類繼承
6.2私有化方法
class A(object):
def __eat(self):
print('吃飯')
pass
pass
def run(self):
print('跑步')
pass
pass
b = A()
b.__eat() ## 報錯
b.run() ## 跑步
7.property方法
屬性函數
class A(object):
def __init__(self):
self.__name = 18
def __eat(self):
return self.__name
pass
pass
def run(self):
print('跑步')
pass
pass
age = property(__eat, run)
b = A()
print(b.age) ## 報錯
b.run() ## 跑步
7.1 @age.setter ##修改屬性
class A(object):
def __init__(self):
self.__name = 18
def __eat(self):
return self.__name
pass
pass
def run(self):
print('跑步')
pass
@property ##添加屬性標識
def age(self):
return self.__name
pass
@age.setter ##修改屬性
def age(self,params):
self.age = params
pass
pass
p1 = A()
print(p1.age) ## 18
p1.age = 16
print(p1.age)
8. __new__方法
作用:創建並返回一個實例對象,如果__new__只調用了一次,就會得到一個對象。繼承自object的新式類,才有new這一魔術方法。
8.1 注意事項
1.__new__是一個實例化調用的第一個方法
2.__new__至少必須有一個參數 cls,代表要實例化的類,此參數在實例化時由python解釋器提供,其他的參數是直接傳遞給__init__方法
3.__new__決定是否使用該__init__方法,因為__new__可以調用其他的類的構造方法或者返回實例對象作為類的實例,如果__new__沒有返回實例,則__init__不會被調用
4.在__init__方法中,不能調用自己的__new__方法,return cls__new__(cls),否則會報錯。
class A(object):
def __init__(self):
print('__init__執行了')
pass
pass
def __new__(cls,*args,**kwargs):
return super().__new__(cls,*args,**kwargs)
pass
pass
a = A()
print(a)
__init__執行了
<__main__.A object at 0x00000291F97D5160>
## 當__new__返回的時候 __init__才會顯示
9.單例模式
9.1 確保一個類只有一個實例存在,使用__new__
class DataBaseClass(object):
def __new__(cls,*args,**kwargs):
## cls._instance = cls.__new__(cls) ##不能使用自己的new方法
if not hasattr(cls,'_instance'):
cls._instance = super().__new__(cls,*args,**kwargs)
return cls._instance
pass
pass
db1 = DataBaseClass()
db2 = DataBaseClass()
db3 = DataBaseClass()
print(id(db1))
print(id(db2))
print(id(db3))
## 三個指向的內存地址都一樣的
## 1852298514784
## 1852298514784
## 1852298514784
10 錯誤和異常處理
try:
## 可能出現錯誤的代碼塊
except:
## 出錯之後執行的代碼塊
else:
## 沒有出錯的代碼塊
finally:
## 不管有沒有出錯,都會執行
10.1 錯誤和異常處理示例
try:
## 可能出現錯誤的代碼塊
li = [1,2,3]
## print(li[10])
print(1/0)
except IndexError as msg:
## 出錯之後執行的代碼塊
print(msg)
except ZeroDivisionError as msg:
## 出錯之後執行的代碼塊
print(msg)
else:
## 沒有出錯的代碼塊
print('沒有出錯了')
finally:
## 不管有沒有出錯,都會執行
print('出錯了')
## 用一個try可以捕獲多個不同類型的異常
10.2 使用 Exception處理所有錯誤
try:
print(b)
except Exception as result:
print(result)
else:
print('出錯了')
finally:
print('出錯了')
10.3在合適的層次去捕獲
def A(s):
return s/int(s)
pass
def B(s):
return A(s)/2
pass
def main():
try:
B(0)
except Exception as result:
print(result)
main()
在合適的位置進行錯誤捕獲
division by zero
10.4 異常運行機制
1、解釋器會查找相應的異常捕獲類型
2、不斷傳遞給上層,沒有找到異常處理,會退出
11.自定義異常類型
class ToolongException(Exception):
def __init__(self, len):
self.len = len
def __str__(self):
return '輸入的長度是'+str(self.len)+'長度,超出長度了'
def name_test():
name = input('輸入名字')
try:
if len(name)>5:
raise ToolongException(len(name))
else:
print(name)
except ToolongException as result:
print(result)
else:
print('沒有出錯了')
name_test()
##輸入的長度是13長度,超出長度了
12 動態添加屬性和方法
import types
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
pass
pass
def __str__(self):
return '{}今天{}歲了'.format(self.name, self.age)
pass
pass
zhz = Student('詹躲躲', 25)
zhz.wight = 60
def dymicMethod(self):
print('{}體重是{}'.format(self.name,self.wight))
pass
## 動態添加屬性
print(zhz.wight)
## 類添加屬性
Student.pro = '計算機科學'
## 實例可以訪問
print(zhz.pro)
## 動態添加實例方法
## import types
zhz.printInfo = types.MethodType(dymicMethod,zhz)
zhz.printInfo()
## 詹躲躲體重是60
13 動態綁定類方法
import types
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
pass
pass
def __str__(self):
return '{}今天{}歲了'.format(self.name, self.age)
pass
pass
zhz = Student('詹躲躲', 25)
zhz.wight = 60
def dymicMethod(self):
print('{}體重是{}'.format(self.name,self.wight))
pass
## 動態綁定類方法
@classmethod
def classTest(cls):
print('類方法')
pass
## 動態綁定靜態方法
@staticmethod
def staticTest():
print('靜態方法')
pass
13.1.動態添加屬性
print(zhz.wight)
13.2.類添加屬性
Student.pro = '計算機科學'
## 實例可以訪問
print(zhz.pro)
13.3.動態添加實例方法
## import types
zhz.printInfo = types.MethodType(dymicMethod,zhz)
zhz.printInfo()
13.4.動態綁定類方法
Student.testMethod = classTest
Student.testMethod()
13.5.動態綁定類方法 實例調用
zhz.testMethod()
13.6.動態綁定靜態方法
Student.statictest = staticTest
Student.statictest()
13.7.動態綁定靜態方法 實例調用
zhz.statictest()
14._slots_屬性
class Student(object):
__slots__ = ('name', 'age', 'score')
def __str__(self):
return "{},{}".format(self.name, self.age)
xw = Student()
xw.name = '叫我詹躲躲'
xw.age = 25
## print(xw.__dict__)
## {'name': '叫我詹躲躲', 'age': 25}
xw.s11 = '1212'
#### 報錯
print(xw)
子類未聲明 __slots__,不會繼承父類的__slots__,此時子類可以隨意的屬性賦值
子類聲明瞭,範圍為 子類+父類的範圍
15.題目練習 一
15.1 python new的方法和作用是什麼?
用來創建實例對象,只有繼承了object的話,才有這個方法。
15.2 什麼是單例模式,適用於什麼場景?
要求一個類有且只有一個實例,並且提供了全局的訪問點。日誌插入logger,網站計數器,權限驗證模塊,window資源管理器,系統回收站,數據庫連接池
15.3 私有化方法和私有化屬性在子類中能否繼承?
不能的
15.4 在python中什麼是異常?
程序在執行中出現的異常。
15.5 python中如何處理異常?
分別根據異常的類型去處理
15.6 python中異常處理的一般格式,可以使用偽代碼描述?
## try:
## 正常操作
## except:
## ##....
## else:
## ##....
## finally:
## ##...
15.7 __slots__的作用
限制屬性的隨意輸入,節省內存空間
15.8 私有化的屬性的作用?
保護數據,封裝性的體現
15.9 在類外是否修改私有屬性?
不可以直接修改,通過方法去實現,可以藉助property
15.10 如果一個類,只有指定的屬性或者方法能被外部修改,該如何限制?
對屬性進行私有化
16 題目練習二
16.1 定義一個person類,類中要有初始化方法,方法中要有人名,年齡兩個私有屬性
提供獲取用户信息的函數,提供設置私有屬性的方法,設置年齡在0-120歲中間,如果不在這個範圍,不能設置成功
class Person:
def __init__(self,name,age):
self.__name = name
self.__age = age
pass
pass
def GetUserInfo(self):
return "{}的年齡為{}".format(self.__name,self.__age)
pass
pass
def __str__(self):
return "{}的年齡為{}".format(self.__name,self.__age)
def setAge(self,age):
if age>0 and age<120:
self.__age = age
else:
pass
person = Person('詹躲躲',19)
print(person.GetUserInfo())
## 詹躲躲的年齡為19
print(person.setAge(30))
print(person.GetUserInfo())
## 詹躲躲的年齡為30
16.2 請寫一個單例模式
class DataBaseClass(object):
def __new__(cls,*args,**kwargs):
## cls._instance = cls.__new__(cls) ##不能使用自己的new方法
if not hasattr(cls,'_instance'):
cls._instance = super().__new__(cls,*args,**kwargs)
return cls._instance
pass
pass
db1 = DataBaseClass()
db2 = DataBaseClass()
db3 = DataBaseClass()
print(id(db1))
print(id(db2))
print(id(db3))
16.3 創建一個類,並定義兩個私有化屬性,提供一個獲取屬性的方法。利用property屬性給調用者提供調用
class Student:
def __init__(self, name, score):
self.__name = name
self.___score = score
@property
def name(self):
return self.__name
@name.setter
def name(self, name):
self.__name = name
def __str__(self):
return self
def __call__(self, *args, **kwargs):
print(self.name)
pass
pass
xm = Student('詹躲躲',98)
xm.__call__()
xm.name()
16.4 創建一個Animal類。實例一個cat對象,給cat 綁定一個run方法,給類綁定一個類屬性color
import types
class Animal:
pass
def run(self):
print('小貓')
cat = Animal()
cat.run = types.MethodType(run,cat)
cat.run()
Animal.color = 'red'
print(cat.color)
def info():
print('ok')
Animal.info = info
Animal.info()
原創:叫我詹躲躲
來源:思否
鏈接:python面型對象編程進階(繼承、多態、私有化、異常捕獲、類屬性和類方法)
致謝:感謝求知教育提供的視頻教程