物件導向 -- 三大特性之封裝

想吃橙子發表於2019-03-30

封裝

隱藏物件的屬性和實現細節,僅對外提供公共訪問模式

好處

將變化隔離

便於使用

提高複用性

提高安全性

封裝原則

將不需要對外提供的內容都隱藏起來

把屬性都隱藏,提供公共方法對其訪問

如果不想讓別人改我的屬性 或者乾脆就不想讓別人看到 那麼可以使用私有化的方法和屬性

什麼是私有化

所謂的私有化就是隻能在類的內部可見,類的外部是不能訪問或檢視的

私有化是怎麼完成的

所有的私有化的變化都是在類的 [內部] 完成的

方法/靜態變數/例項變數(物件屬性)都可以私有化

私有的物件屬性

class Goods:
    def __init__(self,name,price):
        self.name = name
        self.__price = price    # 私有屬性

    def get_price(self):
        print(self.__price)

apple= Goods('蘋果',5)
print(apple.name)
# print(apple.__price)#這種方法不可以,物件屬性已經被私有化了,不能直接列印
apple.get_price()
print(apple._Goods__price)
因為私有化在類的內部可見,所以可以在類的內部設定一個檢視私有化物件屬性的函式,在類的外部呼叫這個函式,就可以檢視私有化的物件屬性

私有的靜態變數

class Role:
    __Country='China'   # 靜態變數的私有化
    def func(self):
        print(self.__Country)
#print(Role.__Country)  # 報錯 : 因為不能再類的外部引用變數
Role().func()  #可以不需要self,直接例項化,再呼叫類的內部方法

私有的方法

class Big(object):
    def __init__(self,name,money):
        self.name = name
        self.money = money

    def pay(self):
        print('%s成功消費了%s元'%(self.name,self.money))

    def __back(self):
        print('%s已退款%s元'%(self.name,self.money))
alex = Big('alex',100)
alex.pay()
alex._Big__back()

私有的屬性可以被繼承嗎?

先看幾個程式碼

class Foo:
    def __init__(self):
        self.__func()

    def __func(self):
        print('in foo')

class Son(Foo):
    def __func(self):
        print('in son')

Son()

例項化Son後先去父類中的 __init__ 之後變為 _Fon__func()
回到自己的類中,並沒有可以呼叫的方法,去父類中尋找
可以呼叫父類中的 __func() 
於是輸出結果為 in foo
class User:
    def func(self):
        self.__wahaha()  #在所有的空間裡找不到 _User__wahaha

class VipUser(User):
    def __wahaha(self):
        print('in vip user')

VipUser().func()  #報錯

例項化Vipuser後要進行func方法的呼叫
在自己的類中沒有找到,在父類中找到了,但父類中的方法被私有化了
於是變為 _User__wahaha
而在所有的空間中都找不到 _User__wahaha 可以呼叫的方法
於是輸出結果為報錯
class User:
    def __wahaha(self):
        print('in user')

class VipUser(User):
    def func(self):
        self.__wahaha()

VipUser().func()    # 報錯,因為在名稱空間中根本不存在一個_VipUser__wahaha
輸出結果為報錯
原因與上一例子相同

私有的這個概念,但凡在類的外部,都不能用

私有的所有內容:例項變數(物件屬性)靜態變數(類變數),方法都不能被子類繼承

小總結

公有的  在類的內部外部隨便使用

保護的  (其他語言)

私有的  只能在類的內部使用 既不能被繼承,也不能在類的外部使用

property

property是一個內建函式,作用是把被自己裝飾以一個方法偽裝成一個屬性

寫程式碼時候可以用到,讓程式碼更有邏輯性

class Circle:
    def __init__(self,r):
        self.r = r

    @property  # 把裝飾的一個方法偽裝成一個屬性
    def area(self):
        return 3.14*self.r**2

    @property
    def perimeter(self):
        return 2*3.14*self.r

c1 = Circle(5)
c1.r=10
print(c1.area)                                  #想使用area方法,只要像檢視屬性一樣用類名 + . + 方法名就可以實現                 print(c1.perimeter)

property和私有概念

可以創造出一個屬性,只能看,不能改

class Goods:
    def __init__(self,name,price):
        self.name = name
        self.__price = price

    @property
    def price(self):
        return self.__price

apple = Goods('蘋果',5)
print(apple.name)
print(apple.price)

但如果想要修改的話,就要引入另一個函式

setter

class Goods:
    discount = 0.8

    def __init__(self, name, price):
        self.name = name
        self.__price = price

    @property
    def price(self):
        p =  self.__price * self.discount
        return p


apple = Goods('蘋果', 5)
banana = Goods('香蕉', 10)
print(apple.name)
print(apple.price)
print(banana.price)
Goods.discount = 1
print(apple.price)
print(banana.price)

如果想在類的內部修改 price 的值

class Goods:
    discount = 0.8

    def __init__(self, name, price):
        self.name = name
        self.__price = price

    @property    # 只支援obj.price的方式檢視這個結果,不支援修改,也不支援刪除
    def price(self):
        p =  self.__price * self.discount
        return p

    @price.setter
    def price(self,value):
        if type(value) is int or type(value) is float:
            self.__price = value

apple = Goods('蘋果', 5)
banana = Goods('香蕉', 10)
apple.price = 16   # 對應的呼叫的是被setter裝飾的price方法
print(apple.price)  # 對應呼叫的是被property裝飾的price方法
如果我們定義的是普通的變數或者屬性
    那麼這個屬性可以從外部直接訪問
    可以任意的修改 obj.attr = 123
    甚至可以刪除 del obj.attr
私有化
    把一個屬性加上雙下劃線 __屬性名
    這個屬性就連在外面看都看不見了
    我們實際上有些場景允許別人看,不許改
        __屬性
        @property裝飾的屬性名
        def 屬性():

    我們允許別人看,也允許別人改,但是不能瞎改,有一些要求:資料型別 範圍
        __屬性
        @property裝飾的屬性名
        def 屬性():return __屬性

        @屬性.setter
        def 屬性(self,value):
            加點兒條件
            修改__屬性
class Goods:
    discount = 0.8

    def __init__(self, name, price):
        self.name = name
        self.__price = price

    @property    # 只支援obj.price的方式檢視這個結果,不支援修改,也不支援刪除
    def price(self):
        p =  self.__price * self.discount
        return p

    @price.setter
    def price(self,value):
        if type(value) is int or type(value) is float:
            self.__price = value

    @price.deleter
    def price(self):
        del self.__price

# 想刪除一個屬性
apple = Goods('蘋果', 5)
del apple.price
print(apple.__dict__)
apple.price
apple.price = 9
私有的 :通過過給__名字這樣的屬性或者方法加上當前所在類的字首,把屬性隱藏起來了
        只能在本類的內部使用,不能在類的外部使用,不能被繼承
property 把一個方法偽裝成屬性
property和私有的兩個概念一起用
    定義一個私有的
    再定義一個同名共有的方法,被property裝飾

    @方法名.setter
    @方法名.deleter

classmethod 和 staticmethod

classmethod

class Fruits:
    __discount = 0.8

    def __init__(self, name, price):
        print('init',self)
        self.name = name
        self.__price = price

    @classmethod      # 把一個方法從物件方法,變成一個類方法
    def change_discount(cls,value):
        cls.__discount = value   # cls到底是誰??? Fruits

    @classmethod
    def get_discount(cls):
        return cls.__discount

print(Fruits.get_discount())
Fruits.change_discount(1)
print(Fruits.get_discount())

# 類方法
    # 1. 有些時候我們要修改的是類中的靜態變數/類變數
    # 此時根本不會和self有任何的操作關聯
    # 這時傳一個self引數對我們來說完全沒有用
    # 我們希望接受的是當前我們所在的類

apple = Fruits('apple',8)
apple.change_discount(0.5)
print(Fruits.get_discount())

# 類方法推薦使用類名呼叫而不是使用物件名呼叫

staticmethd

class A:
    @staticmethod  # 宣告這個方法只是一個普通的不會使用任何和這個類中的變數相關的方法
    def func():    # 此時 func是一個靜態方法
        print('既不操作和self相關的內容')
        print('也不操作和類名相關的內容')

A.func()


# login 登入

class Student:
    def __init__(self,name):
        self.name = name

    @staticmethod
    def login():
        pass

# 先獲取這個學生的使用者名稱和密碼
# 判斷他登入成功之後進行例項化
# Student.login()
# stu = Student('alex')

相關文章