python 類的封裝/property類型/和對象的綁定與非綁定方法

類的封裝

封裝: 就是打包,封起來,裝起來,把你丟進袋子裏,而後用繩子把袋子綁緊,你還能拿到袋子裏的那我的嗎?函數

1.隱藏屬性和方法,外部(類的外部)沒法使用,內部(類額內部)可使用,在類定義階段就執行了,真的想引用,就使用_類名__屬性名學習

封裝分爲兩個層面:優化

第一個層面: 對象能拿到類的東西,可是類能拿到對象的東西嗎?編碼

class Foo():
    count = 0
    print(count)
f = Foo()
print(f.count)
f.name = 'nick'  # 對 對象進行了封裝,類拿不到對象的name
print(Foo.name) # AttributeError: type object 'Foo' has no attribute 'name'

AttributeError 英文:屬性錯誤的意思code

第二個層面的: 內部(類的內部)可使用,外部(類的外部)不可使用,在你須要封裝的屬性前面加上__對象

# 之前定義變量並不會如下劃線開頭,如下劃線開頭的變量,好比隱藏屬性,或者如下劃線開頭方法,在某種狀況下會自動調用,好比__init__()
lass People():
    lover = 'male'
    print('in',lover) # 內部可用lover
    print('out',People.lover) # 外部可用lover 


# 屬性隱藏,在屬性前加__
class People():
    __lover = 'male'
    print('in',__lover) # 內部可用__lover
# print('out',People.__lover) # 外部不能夠用__lover
print('out',People._People__lover) # out male    若是你真的要拿,_類名__屬性去拿(不可能這樣作)

# 函數隱藏,在函數前加__函數名
# 正常
class People():
    def eat(self):
        print('eat')
People.eat(111) # 類調用,須要傳參
pe = People()
pe.eat()

# 隱藏方法 
class People():
    __love_people = 'male'
    # print('in',love_people)   報錯
    # print('in',__love_people) 報錯
    # 定義一個吃飯的流程:拿碗,拿筷子,吃飯
    def __nawan(self):
        print('nawan')
    def __nakuaizi(self):
        print('nakuaizi')
    def __chifan(self):
        print('chifan')

    def chifan_all(self): # 吃飯
        self.__nawan()
        self.__nakuaizi()
        self.__chifan()


# print('out',People.__nawan(11)) # 報錯,不能夠引用內部的__nawan函數,函數進行了隱藏

p  = People()
# print('out',p.nawan())
# print('out',p.nakuaizi())
# print('out',p.chifan())

print('out',p.chifan_all())

2.隱藏模塊內的函數/變量 _x: from module import * (沒法導入),from module import _x(不合理)it

# 正常狀況下
# m1.py
x= 10
def f1():
    print('from f1')
# m2.py
from m1 import x
# from m1 import *
print(x)
f1()

#如今對模塊內的函數/變量 進行隱藏
# m1.py
_x= 10
def __f1():
    print('from f1')
# m2.py
from m1 import _X,__f1 (能夠導入_x,__f1,可是不合理,變量/函數前面加_或者__都行,主要原模塊m1中變量或者函數名寫成什麼樣,m2單獨導入就導什麼樣)
# from m1 import * (導不出_x,__f1) ,除掉註釋,下面兩行代碼都會報錯
print(_x) # 能夠導入
__f1()    # 能夠導入

對屬性這個封裝有什麼用:藏起來了,保護了你的隱私,類內部的屬性不想讓其餘人訪問io

對方法封裝有什麼好處:精簡了代碼,你吃飯就使用chifan_all這個方法就能夠了,不須要去關心其餘的操做,而且外部調用者也不知道你內部發生了什麼function

作一個小練習,理解封裝其實在定義階段就已經執行了,會把私有屬性__f1變成 _Foo__f1,以後都不會作這種處理

class Foo:
    def __f1(self):
        print('Foo.f1')
    def f2(self):
        print('_Foo__f1')
        self.__f1() 
print(Foo.__dict__) #注意字典中 __f1 變成了什麼,_Foo__f1    {'__module__': '__main__', '_Foo__f1': <function Foo.__f1 at 0x00000231DCBE0488>, 'f2': <function Foo.f2 at 0x00000231DCBE0510>, '__dict__': <attr


class Bar(Foo):
    def __f1(self):
        print('Bar.f1')
        
bar = Bar() # 實例化一個對象
bar.f2()  # 對象bar中找f2,沒有,而後Bar類也沒有,去父類Foo找,找到f2,打印 _Foo__f1,再執行self.__f1(),self是對象,對象有__f1,打印 Bar.f1
bar.f2() # _Foo__f1,Bar.f1
class Foo():
    __count = 0

foo = Foo()
print(foo)

foo.__y = 1 # 給對象foo添加屬性__y
print(foo.__y) # 1

類的property特性

@property : 被@property 裝飾的函數會從函數變成屬性,也就是說直接 .函數名,不須要加括號使用

# BMI

class People():

    def __init__(self,height,weight):
        self.height = height
        self.weight = weight

    @property
    def bmi(self):
        return self.weight/(self.height**2)

peo = People(1.8,70)
print(peo.height)
# print(peo.bmi()) 沒用 @property的時候須要這樣寫
print(peo.bmi)

@方法名.setter : 被@方法名.setter 裝飾的函數,方法名修改,會執行這個裝飾的函數

@方法名.deleter: 被@方法名.deleter 裝飾的函數,方法名刪除,會執行這個裝飾的函數

# 裝飾器用法(只在Python3中使用)
class People():

    def __init__(self,height,weight):
        self.height = height
        self.weight = weight

    @property  # 獲取值的時候觸發,你不須要加括號使用,不能加參數
    def bmi(self):
        return self.weight/(self.height**2)

    @bmi.setter  # 在修改bmi的時候觸發,必須得加參數
    def bmi(self, value):
        print(f'你已經成功修改成{value}')

    @bmi.deleter  # 在刪除bmi的時候觸發,不能加參數
    def bmi(self):
        print('delter')

peo = People(1.8,70)
print(peo.bmi)

print('*'*50)
peo.bmi = 50

print('*'*50)
del peo.bmi

類與對象的綁定方法與非綁定方法

綁定方法: 綁定的方法

1.對象的綁定方法:沒有加任何裝飾的方法就是對象的綁定方法

2.類的綁定方法: 加了@classmethod裝飾器的方法就是類的綁定方法

3.非綁定方法: 加了@staticmethod裝飾器的方法就是非綁定方法,其實就是一個普通的函數

@property 讓函數方法 bmi() 變成屬性,
@bmi.setter 和 @bmi.deleter 讓這個函數方法 bmi() 能夠進行屬性同樣的修改和刪除,
因此 @bmi.setter 和 @bmi.deleter 裝飾的函數方法名必須是property裝飾的函數方法名bmi(),而不能夠是隨意定義的函數名字,若是換成其餘名字會報錯,顯示的就是該屬性(實際是個函數)沒法進行修改或刪除。

隨意定義函數方法名是 類屬性方法使用property 能夠擁有的

class Foo:
    # 綁定給對象,只有對象能用,可是類也能使用,使用的時候必須得傳參
    def f1(self):
        print(self)

    @classmethod  # 讓被裝飾的函數給類使用,約定俗稱參數爲cls
    # 綁定給類的方法,類能使用,對象也可使用,可是參數依然是類
    def f2(cls):
        print(cls)

    # 什麼都不綁定的,非綁定方法,定義了普通的函數
    @staticmethod
    def f3(self):
        print(self)

f = Foo()
f.f1()
Foo.f1(1111)

print('*' * 50)
Foo.f2()
f.f2()

print('*'*50)
Foo.f3(2222)
f.f3(2222)  # f爲對象,但f3爲普通函數,該傳什麼參就傳什麼參
<__main__.Foo object at 0x000002C80DCBC828>
1111
**************************************************
<class '__main__.Foo'>
<class '__main__.Foo'>
**************************************************
2222
2222

🌸🌸🌸🌸🌸🌸🌸🌸🌸🌸

學習python已有月把時間,強烈推薦小夥伴們要開始培養本身優化代碼的思惟了

《編寫高質量代碼:改善python程序的91個建議》

《編寫高質量python代碼的59個有效方法》--》改善代碼的風格

《流暢的python》--》面向對象

以上三本書看不懂的跳過,是潛移默化去薰陶編碼的思惟,代碼寫得更精簡優美,不要去深究,若是想深刻,之後有時間再探究😂

相關文章
相關標籤/搜索