Python Day 26 封裝、property裝飾器、多態、__str__內置函數、__del__內置函數、反射、動態導入模塊

  閱讀目錄python

   

一、封裝
二、封裝屬性
三、封裝方法
四、封裝原理
五、property裝飾器
六、多態
七、__str__內置函數
八、__del__內置函數
九、反射
十、動態導入模塊
十一、反射在框架中的應用

 

  ##封裝安全

#什麼是封裝?
對外部隱藏內部的屬性,以及實現細節  , 給外部提供使用的接口 

注意:封裝有隱藏的意思,但不是單純的隱藏 

學習封裝的目的.就是爲了可以限制外界對內部數據的訪問 

python中屬性的權限分爲兩種

1.公開的

​    沒有任何限制 誰都能訪問 

2.私有的 

​    只有當前類自己可以訪問 
默認爲公共的
 
#爲何須要封裝
1.提升安全性  

​    封裝屬性    

2.隔離複雜度     

​    封裝方法

#一個類中分爲兩種數據,屬性和方法

#如何封裝
在屬性名或者方法名前添加兩個下劃線,將其設置爲私有的

#思考:封裝能夠明確地區份內外,封裝的屬性能夠直接在內部使用,而不能被外部直接使用,然而定義屬性的目的終歸是要用,外部要想用類隱藏的屬性,須要爲其提供接口,
讓外部可以間接地使用到隱藏起來的屬性,那這麼作的意義何在?
   答:能夠在接口附加上對該數據操做的限制,以此完成對數據屬性操做的嚴格控制。


__

  ##封裝屬性框架

class Student:
    def __init__(self,name,age,gender,id_card):
        self.name = name
        self.age = age
        self.gender = gender
        self.__id_card = id_card


    # 訪問器
    def get_id_card(self,pwd):
        # 能夠在這裏添加額外的任何邏輯代碼 來限制外部的訪問
        # 在類的內部 能夠訪問
        if pwd =="123":
            return self.__id_card
        raise Exception("密碼錯誤!")


    # 修改被封裝的屬性   稱之爲設置器
    def set_id_crad(self,new_id):
        # 身份證必須是字符串類型
        # 長度必須是18位
        if isinstance(new_id,str) and len(new_id) == 18:
            self.__id_card = new_id
        else:
            raise Exception("身份證號碼 必須是字符串 且長度必須爲18!")

# stu1 = Student("rose",20,"man","111111111111111111")
#
# print(stu1.name)
# print(stu1.id_card)
# stu1.id_card = "123"
# print(stu1.id_card)

stu1 = Student("rose",20,"man","111111111111111111")
# print(stu1.id_card)
# print(stu1.__id_card)
# stu1.show_id_card()
# stu1.set_id_crad("222222222222222222")

# stu1.show_id_card()

# id = stu1.get_id_card()
# print(id)

# stu1.set_id_crad(123)
stu1.set_id_crad("555555555555555555")
# print(stu1.get_id_card())

print(stu1.get_id_card("1232"))

  ##封裝方法函數

什麼樣的方法應該被封裝起來 ?

​    答:一個爲內部提供支持的方法,不該該讓外界直接訪問,那就封裝起來 ,以下例中的 user_auth等...

#示例1
class ATM:

    def withdraw(self):
        self.__user_auth()
        self.__input_money()
        self.__save_record()
        # 輸入帳號和密碼
        # 顯示餘額
        # 輸入取款金額
        # 保存記錄

    def __user_auth(self):
        print("請輸入帳號密碼....")

    def __input_money(self):
        print("餘額爲100000000,請輸入取款金額!")

    def  __save_record(self):
        print("記錄流水....")
atm = ATM()
# atm.user_auth()
# atm.input_money()
# atm.save_record()

# atm.withdraw()

# atm.save_record()

  ##封裝原理學習

python是經過 變形的方式來實現的封裝
如何變形 在名稱帶有雙下劃線開頭的變量名字前添加_類名  如_Person__id_card
固然經過變形後的名字能夠直接訪問被隱藏的屬性  但經過不該該這麼作
變形僅在類的定義階段發生一次 後續再添加的帶有雙下劃線的任何屬性都不會變形  就是普通屬性 

#示例1
class Person:
    def __init__(self,name,age,id_card):
        self.name = name
        self.age = age
        self.__id_card = id_card

    def get_id_card(self):
        return self.__id_card

p = Person("rose",20,"321123123123123123")
print(p.name)


# p.__id_card = "321"
# print(p.__dict__)

# print(p._Person__id_card)
p.__gender = "man"

print(p.__dict__)

  ##property裝飾器ui

做用: 將一個方法假裝成普通屬性 

爲何用 property    但願將訪問私有屬性和普通屬性的方式變得一致

與property相關的 兩個裝飾器 

setter 

​    用點語法 給屬性賦值時觸發   

deleter 

​    用點語法刪除屬性時觸發 

#示例
class Teacher:
    def __init__(self,name,age,salary):
        self.name = name
        self.age = age
        self.__salary = salary

    @property  # getter   # 用於訪問私有屬性的值   也能夠訪問普通屬性
    def salary(self):
        return self.__salary

    @salary.setter   # 用來設置私有屬性的值  也能夠設置普通屬性
    def salary(self,new_salary):
        self.__salary = new_salary

    @salary.deleter # 用來設置私有屬性的值  也能夠刪除普通屬性
    def salary(self):
        # print("can not delete salary!")
        del self.__dict__["_Teacher__salary"]
        # del self.__salary

    #一般property 用於操做私有的屬性
t = Teacher("egon",38,100000)
#
# print(t.get_salary())
#
# t.set_salary(5000)
#
# print(t.get_salary())
# print(t.name)

# 被封裝的屬性在訪問時  須要調用方法  而普通屬性直接點就ok 這樣一來對於對象的使用者而言
# 必須知道要訪問的屬性 是私有的仍是公開 而後調用對於的方法    用起來麻煩
# 此時  咱們的目標是 讓訪問私有屬性 和訪問普通屬性的方式一直
# property 裝飾器  就是用來將一個方法假裝成屬性


# print(t.salary)
# t.salary = 500
# print(t.salary)

# 刪除對象屬性
# del t.name
#
# print(t.name)


# del t.salary


# a = {"name":123}
# # a.pop("name")
#
# del a["name"]
#
# print(a)

del t.salary
#
# t.del_salary()


# t.salary = 1
#
#
# # print(t.salary)
#
# del t.salary


# t.get_salary()
# t.set_salary(800)
# t.delete_salary()

# t.salary
# t.salary = 800
# del t.salary

  ##property的另外一種使用場景:計算屬性this

什麼是計算屬性   一個屬性 它的值不是固定死的 而是經過計算動態產生的。
例如:BMI指數

#示例1
class Person:
    def __init__(self,name,height,weight):
        self.name = name
        self.height = height
        self.weight = weight
        # self.BMI = weight / (height ** 2)
    @property
    def BMI(self):
        return self.weight / (self.height ** 2)

    @BMI.setter
    def BMI(self,new_BMI):
        print("BMI 不支持自定義.....")

p = Person("egon",1.7,80)
# print(p.BMI)
#
#
# p.weight = 60
# print(p.BMI)


# print(p.get_BMI())
# p.weight = 60
#
# print(p.get_BMI())
#
# print(p.name)
# print(p.get_BMI())

#
# print(p.BMI)
# p.weight = 60
# print(p.BMI)
# p.BMI = 10

  ##封裝能不能被繼承問題spa

# 被封裝的內容(私有的)  不能夠被繼承
# class A:
#     __name =  "rose"  # _A__name
#
#     def __say_hi(self):
#         print("A say: hi")
# class B(A):
#     def test(self):
#         # print(super().__name)  #_B__name
#         print(A._A__name)
#     # pass
# b = B()
# b.test()

  ##多態設計

多態不是一個具體的技術  或代碼

指的是 多個不一樣類型對象 能夠響應同一個方法 ,產生不一樣結果

例如 水:   氣態  固態  液態
     動物: 人  貓  豬
     汽車人:  汽車 飛機  人型

OOP中 標準解釋: 多個不一樣類型對象 能夠響應同一個方法  而且產生不一樣結果

多態的帶來的好處:
    只須要學習基類中的使用方法便可, 不須要關心具體的哪個類 以及實現的   以不變應萬變   提升了靈活性
    提升擴展性 
    
    若是沒有多態  須要分別學習 person  cat pig 的不一樣使用方法 這對於使用者而言太麻煩了

如何實現多態:
    鴨子類型 就是典型的多態 多種不一樣類型 使用方法同樣 

#示例1
class Person():

    def bark(self):
        print("Hello!")

    def run(self):
        print("兩條腿跑!")

    def sleep(self):
        print("躺着睡!")


class Cat():

    def bark(self):
        print("喵喵喵")

    def run(self):
        print("四條腿跑!")

    def sleep(self):
        print("趴着睡!")

class Pig():
    def bark(self):
        print("哼哼哼!")

    def run(self):
        print("四條腿跑!")

    def sleep(self):
        print("側躺着睡!")


# person1 = Person()
# cat1 = Cat()
# pig1 = Pig()

# person1.sleep()
# cat1.sleep()
# pig1.sleep()
# 若是沒有多態  須要分別學習 person  cat pig 的不一樣使用方法 這對於使用者而言太麻煩了
#

# 一個用來管理動物的方法   只要你傳入是一個動物 我就按照動物的標準來使用 徹底不用考慮你具體是什麼類型

class Dog:
def bark(self):
print('汪汪汪')
def run(self):
print('四條腿在跑')
def sleep(self):
print('躺着睡')
class Cat:
def bark(self):
print('喵喵喵')
def run(self):
print('四條腿在跑')
def sleep(self):
print('趴着睡')
def manage_animal(animal):
print('========%s====='%animal.__class__.__name__)
animal.bark()
animal.run()
animal.sleep()
dog = Dog()
manage_animal(dog)

cat = Cat()
manage_animal(cat)
 
 
#  無處不在的多態
 
# def MY_LEN(obj):
#     return obj.__len__()
#
# print(MY_LEN("abcdefg"))
# print(MY_LEN([1,2,3,4]))
# print(MY_LEN({"name":123}))

print(len("1231212121"))
 
#總結

繼承:是類與類之間的關係,什麼是什麼的關係,好處是經過繼承可使用父類中的屬性和方法code

封裝:對外部隱藏屬性和實現細節,同時提供調用的接口,目的提升數據的安全度 和隔離複雜度

多態:不一樣類型的對象使用同一方法產生不一樣的結果,好處是學習統一標準,提升靈活性和拓展性

  ##經常使用的內置函數

 

#__str__
類中的__str__
    該方法在object中有定義 默認行爲 返回對象類型以及地址  <__main__.Person object at 0x0000016F450C7390>
    在將對象轉爲字符串時執行
    注意:返回值必須爲字符串類型
    子類能夠覆蓋該方法來完成 對打印內容的自定義

#示例1
class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    # 將對象轉換爲字符串時執行
    def __str__(self):
        print("str run")
        return "my name is %s , age is %s" % (self.name,self.age)


p = Person("rose",20)
# print(p) #在打印前都會現將要打印的內容轉爲字符串  經過調用__str__函數

str(p)

#__del__
"""
__del__
當對象被刪除前會自動調用 該方法
聲明時候會刪除對象?
    1.程序運行結束 解釋器退出 將自動刪除全部數據
    2.手動調用del 時也會刪除對象

注意:該函數不是用來刪除對象的

使用場景
當你的對象在建立時,開啓了不屬於解釋器的資源 例如打開了一個文件
必須保證當對象被刪除時 同時關閉額外的資源  如文件


也稱之爲析構函數  構造 的反義詞
    構造 指的是從無到有
    析構 值從有到無
    簡單的說就對象全部數據所有刪除


總結:__del__該函數 用於 在對象刪除前作一些清理操做
"""

#示例1
# 假設要求每個person對象都要綁定一個文件
class Person:
    def __init__(self,name,path,mode="rt",encoding="utf-8"):
        self.name = name
        self.file = open(path,mode,encoding=encoding)



    # 讀取數據的方法
    def read_data(self):
        return self.file.read()


    def __del__(self):
        print("del run!")
        self.file.close()


# p = Person("jack")

# a = 10

# f = open("test.txt")
# print(f.read())
# f.close()

p2 = Person("rose","本週內容")
print(p2.read_data())

  ##反射

#英文中叫檢討 (自省)   

面向對象中的檢討 指的是,一個對象必須具有,發現自身屬性,以及修改自身屬性的能力;   

一個對象在設計初期,可能考慮不夠周全後期須要刪除或修改已經存在的屬性, 和增長屬性 

反射就是經過字符串來操做對象屬性

涉及到的方法:
1、hasattr 判斷是否存在某個屬性

2、getattr    獲取某個屬性的值

3、setattr    新增或修改某個屬性 

4、delattr 刪除某個屬性 

#示例1
import os
class  Student:

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


stu = Student("rose")
# stu.age = 18
#
# print(stu.name)
# print(hasattr(stu,"name"))
print(getattr(stu,"name"))
#
# setattr(stu,"name","jack")
# print(getattr(stu,"name"))
#
# delattr(stu,"name")
# print(stu.name)


#示例2

class MY_CMD:

    def dir(self):
        os.system("dir")

    def ipconfig(self):
        os.system("ipconfig")

cmd = MY_CMD()

while True:
    name = input("請輸入要執行的功能:")
    if hasattr(cmd,name):
        method = getattr(cmd,name)
        print(method)
        method()
    else:
        print("sorry this method is not exists....!")

  ##動態導入模塊

直接寫import 稱之爲靜態導入  創建在一個基礎時 提早已經知道有這個模塊

動態導入  指的是  在須要的任什麼時候候 經過指定字符串類型包名稱來導入須要的模塊
import importlib
mk = importlib.import_module(m_name)
mk 即導入成功的模塊

該方式經常使用在框架中 由於框架設計者不可能提早預知後續須要的模塊和類
動態引入引入一個模塊,name能夠是相對路徑和絕對路徑,若是是相對路徑的話,這package就是相應的包名

#示例 import importlib m_name = input("請輸入要導入的模塊名稱:") #執行要輸入模塊名稱:build_house.core mk = importlib.import_module(m_name) print(mk) from build_house import conf print(conf) 註解:print(mk) 和print(conf) 結果同樣的

  ##反射在框架中的應用

#core.py文件
import importlib
from 代碼.build_house import conf
def building():
    print("毛坯房建造完成.......")
    # 讀取用戶提供配置信息 來加載用戶所須要的一系列裝飾品
    for cls_info in conf.decorations:
        # print(cls_info)
        # 切割類名和模塊路徑
        m_name,cls_name = cls_info.rsplit(".",1)
        # print(m_name,cls_name)
        # 導入模塊
        mk = importlib.import_module(m_name)
        # print(mk)
        # 從模塊中獲取類
        if not hasattr(mk,cls_name):
            continue
        cls = getattr(mk,cls_name)
        obj = cls()
        print(obj)

building()

#conf.py文件
decorations = ["build_house.my_decoration.Table",
               "build_house.my_decoration.Bed",
               "build_house.my_decoration.Light",
               "other_decoration.Sofa"]

#my_decoration.py文件
class Table:
    pass

class Light:
    pass

class Bed:
    pass
相關文章
相關標籤/搜索