類的封裝,property特性,類與對象的綁定方法和非綁定方法,

類的封裝

就是把數據或者方法封裝起來python

爲何要封裝

封裝數據的主要緣由是:保護隱私編程

封裝方法的主要緣由是:隔離複雜度(快門就是傻瓜相機爲傻瓜們提供的方法,該方法將內部複雜的照相功能都隱藏起來了,好比你沒必要知道你本身的尿是怎麼流出來的,你直接掏出本身的接口就能用尿這個功能)編程語言

在編程語言裏,對外提供的接口(接口可理解爲了一個入口),就是函數,稱爲接口函數,這與接口的概念還不同,接口表明一組接口函數的集合體。函數

兩個層面的封裝

第一個層面

第一個層面的封裝(什麼都不用作):建立類和對象會分別建立兩者的名稱空間,咱們只能用類名.或者obj.的方式去訪問裏面的名字,這自己就是一種封裝code

注意:對於這一層面的封裝(隱藏),類名.和實例名.就是訪問隱藏屬性的接口對象

第二個層面的封裝

第二個層面的封裝:類中把某些屬性和方法隱藏起來(或者說定義成私有的),只在類的內部使用、外部沒法訪問,或者留下少許接口(函數)供外部訪問。繼承

在python中用雙下劃線的方式實現隱藏屬性(設置成私有的)接口

類中全部雙下劃線開頭的名稱如__x都會自動變造成:_類名__x的形式:md5

class A:
    __N = 0  # 類的數據屬性就應該是共享的,可是語法上是能夠把類的數據屬性設置成私有的如__N,會變形爲_A__N

    def __init__(self):
        self.__X = 10  # 變形爲self._A__X

    def __foo(self):  # 變形爲_A__foo
        print('from A')

    def bar(self):
        self.__foo()  # 只有在類內部才能夠經過__foo的形式訪問到.

這種自動變形的特色:utf-8

  1. 類中定義的__x只能在內部使用,如self.__x,引用的就是變形的結果。
  2. 這種變形其實正是針對內部的變形,在外部是沒法經過__x這個名字訪問到的。
  3. 在子類定義的__x不會覆蓋在父類定義的__x,由於子類中變造成了:_子類名__x,而父類中變造成了:_父類名__x,即雙下滑線開頭的屬性在繼承給子類時,子類是沒法覆蓋的。

注意:對於這一層面的封裝(隱藏),咱們須要在類中定義一個函數(接口函數)在它內部訪問被隱藏的屬性,而後外部就可使用了

這種變形須要注意的問題是:

  1. 這種機制也並無真正意義上限制咱們從外部直接訪問屬性,知道了類名和屬性名就能夠拼出名字:_類名__屬性,而後就能夠訪問了,如a._A__N
  2. 變形的過程只在類的定義時發生一次,在定義後的賦值操做,不會變形
a.__Y = 1
print(a.__dict__)
###
{'_A__X': 10, '__Y': 1}
  1. 在繼承中,父類若是不想讓子類覆蓋本身的方法,能夠將方法定義爲私有的
# 把fa定義成私有的,即__fa
class A:
    def __fa(self):  # 在定義時就變形爲_A__fa
        print('from A')

    def test(self):
        self.__fa()  # 只會與本身所在的類爲準,即調用_A__fa


class B(A):
    def __fa(self):
        print('from B')


b = B()
b.test()
##########
from A

私有模塊

python並不會真的阻止你訪問私有的屬性,模塊也遵循這種約定,若是模塊中的變量名_private_module以單下劃線開頭,那麼from
module import *時不能被導入該變量,可是你from module import
_private_module依然是能夠導入該變量的

類的property特性

什麼是property特性

property裝飾器用於將被裝飾的方法假裝成一個數據屬性,在使用時能夠不加括號而直接使用。

property屬性內部進行一系列的邏輯計算,最終將計算結果返回。

# ############### 定義 ###############
class Foo:
    def func(self):
        pass

    # 定義property屬性
    @property
    def prop(self):
        pass


# ############### 調用 ###############
foo_obj = Foo()
foo_obj.func()  # 調用實例方法
foo_obj.prop  # 調用property屬性`

property屬性的定義和調用要注意一下幾點:

1. 定義時,在實例方法的基礎上添加 @property 裝飾器;而且僅有一個self參數

2. 調用時,無需括號

新式類具備三種@property裝飾器

#coding=utf-8
# ############### 定義 ###############
class Goods:
    """python3中默認繼承object類
        以python二、3執行此程序的結果不一樣,由於只有在python3中才有@xxx.setter  @xxx.deleter
    """

    @property
    def price(self):
        print('@property')

    @price.setter
    def price(self, value):
        print('@price.setter')

    @price.deleter
    def price(self):
        print('@price.deleter')


# ############### 調用 ###############
obj = Goods()
obj.price  # 自動執行 @property 修飾的 price 方法,並獲取方法的返回值
obj.price = 123  # 自動執行 @price.setter 修飾的 price 方法,並將  123 賦值給方法的參數
del obj.price  # 自動執行 @price.deleter 修飾的 price 方法
@property
@price.setter
@price.deleter

新式類中的屬性有三種訪問方式,並分別對應了三個被 @property、@方法名.setter、@方法名.deleter 修飾的方法。必須先有@property

因爲新式類中具備三種訪問方式,咱們能夠根據它們幾個屬性的訪問特色,分別將三個方法定義爲對同一個屬性:獲取、修改、刪除

class Goods(object):
    def __init__(self):
        # 原價
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    @property
    def price(self):
        # 實際價格 = 原價 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    @price.setter
    def price(self, value):
        self.original_price = value

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


obj = Goods()
obj.price  # 獲取商品價格
obj.price = 200  # 修改商品原價
del obj.price  # 刪除商品原價

類屬性方法

建立值爲property對象的類屬性

class Foo:
    def get_bar(self):
        return 'laowang'

    BAR = property(get_bar)


obj = Foo()
reuslt = obj.BAR  # 自動調用get_bar方法,並獲取方法的返回值
print(reuslt)

#laowang

property方法中有個四個參數

  1. 第一個參數是方法名,調用 對象.屬性 時自動觸發執行方法
  2. 第二個參數是方法名,調用 對象.屬性 = XXX 時自動觸發執行方法
  3. 第三個參數是方法名,調用 del 對象.屬性 時自動觸發執行方法
  4. 第四個參數是字符串,調用 對象.屬性.__doc__ ,此參數是該屬性的描述信息
class Goods(object):
    def __init__(self):
        # 原價
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    def get_price(self):
        # 實際價格 = 原價 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    def set_price(self, value):
        self.original_price = value

    def del_price(self):
        del self.original_price

    PRICE = property(get_price, set_price, del_price, '價格屬性描述...')


obj = Goods()
obj.PRICE  # 獲取商品價格
obj.PRICE = 200  # 修改商品原價
del obj.PRICE  # 刪除商品原價

經過使用property屬性,可以簡化調用者在獲取數據的流程

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

綁定方法

對象的綁定方法

在類中沒有被任何裝飾器修飾的方法就是 綁定到對象的方法,這類方法專門爲對象定製。

這類方法不在對象的名稱空間中,而在類的名稱空間中。

經過對象調用綁定到對象的方法,會有一個自動傳值的過程,即自動將當前對象傳遞給方法的第一個參數(self,通常都叫self,也能夠寫成別的名稱);如果使用類調用,則第一個參數須要手動傳值。

p = Person('Kitty', 18)
p.speak()  # 經過對象調用

類的綁定方法

類中使用 @classmethod 修飾的方法就是綁定到類的方法。這類方法專門爲類定製。經過類名調用綁定到類的方法時,會將類自己當作參數傳給類方法的第一個參數。

class Operate_database():
    host = '192.168.0.5'
    port = '3306'
    user = 'abc'
    password = '123456'

    @classmethod
    def connect(cls):  # 約定俗成第一個參數名爲cls,也能夠定義爲其餘參數名
        print(cls)
        print(cls.host + ':' + cls.port + ' ' + cls.user + '/' + cls.password)


Operate_database.connect()

#############
<class '__main__.Operate_database'>
192.168.0.5:3306 abc/123456

經過對象也能夠調用,只是默認傳遞的第一個參數仍是這個對象對應的類。

Operate_database().connect()  # 輸出結果一致

非綁定方法

在類內部使用 @staticmethod 修飾的方法即爲非綁定方法,這類方法和普通定義的函數沒有區別,不與類或對象綁定,誰均可以調用,且沒有自動傳值的效果。

import hashlib


class Operate_database():
    def __init__(self, host, port, user, password):
        self.host = host
        self.port = port
        self.user = user
        self.password = password

    @staticmethod
    def get_passwrod(salt, password):
        m = hashlib.md5(salt.encode('utf-8'))  # 加鹽處理
        m.update(password.encode('utf-8'))
        return m.hexdigest()


hash_password = Operate_database.get_passwrod('lala', '123456')  # 經過類來調用
print(hash_password)
########
f7a1cc409ed6f51058c2b4a94a7e1956
p = Operate_database('192.168.0.5', '3306', 'abc', '123456')
hash_password = p.get_passwrod(p.user, p.password)  # 也能夠經過對象調用
print(hash_password)
###########
0659c7992e268962384eb17fafe88364

簡而言之,非綁定方法就是將普通方法放到了類的內部。

小結

綁定方法

若是函數體代碼須要用外部傳入的類,則應該將該函數定義成綁定給類的方法

若是函數體代碼須要用外部傳入的對象,則應該將該函數定義成綁定給對象的方法

非綁定方法

若是函數體代碼既不須要外部傳入的類也不須要外部傳入的對象,則應該將該函數定義成非綁定方法/普通函數

相關文章
相關標籤/搜索