博客 / 詳情

返回

python面型對象編程進階(繼承、多態、私有化、異常捕獲、類屬性和類方法)

原創:叫我詹躲躲
來源:思否
鏈接: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面型對象編程進階(繼承、多態、私有化、異常捕獲、類屬性和類方法)
致謝:感謝求知教育提供的視頻教程

user avatar u_16213461 頭像
1 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.