繼承下的派生實際應用、面向物件三大特性之封裝、面向物件三大特性之多型、面向物件之反射
阿新 • • 發佈:2022-04-10
繼承下的派生實際應用
import datetime import json class MyJasonEncoder(json.JSONEncoder): def defaule(self,o): # 形參o就是即將要被序列化的資料物件 if isinstance(o,datetime.datetime): return o.strftime('%Y-%m-%d %X') elif isinstance(o,datetime.date): return o.strftime('%Y-%m-%d') return super().default(o) # 呼叫父類 default(讓父類的default方法繼續執行,防止有其他額外的操作) d1 = {'t1':datetime.date.today(),'t2':datetime.date.today()} res = json.dumps(d1,cls=MyJasonEncoder) print(res)
說明:
方法一:手動將不能序列化的型別先轉化為字串
{'t1': str(datetime.datetime.today()), 't2': str(datetime.date.today())}
方法二:研究json原始碼並重寫序列化方法
研究原始碼發現報錯的方法叫default
raise TypeError("Object of type '%s' is not JSON serializable" % o.__class__.__name__)
方法原理就是寫一個類繼承JSONEncoder然後重寫default
面向物件三大特性之封裝
封裝的含義
""" 將類中的某些名字'隱藏'起來,不讓外界直接呼叫 隱藏的目的為了提供專門的通道去訪問,在通道內可以新增額外的功能 """ 實際上,是把該隱藏的隱藏起來,該暴露的暴露出來;Python只需要將類的成員名為以雙下劃線開頭,就可以隱藏類中的成員。
# 如何封裝名字:
在變數名的前面加上兩個下劃線__
封裝的功能只在類定義階段才能生效
在類中封裝其實也不是絕對的,僅僅是做了語法上的變形狀
__變數名 >>>> _類名__變數名
#我們雖然指定了封裝的內部變形語法,但是也不能直接去訪問,看到了就表示這個屬性需要通過特定的通道(介面)去訪問
class Student(object): __school = '清華大學' def __init__(self,name,age): self.__name = name self.__age = age def check_info(self): print('學生姓名:%s' '學生年齡:%s'%(self.__name,self.__age)) def set_info(self,name,age): if len(name) == 0: print('使用者名稱不能為空') return if not isinstance(age,int): print('年齡必須是數字') return self.__name = name self.__age = age stu1 = Student('jason',18) stu1.check_info() stu1.set_info('tuzi',88) stu1.check_info() stu1.set_info('','qweqwe')
將資料隱藏起來就限制了類外部對資料的直接操作,然後類內應該提供相應的介面來允許類外部間接的操作資料
介面之上可以附加額外的邏輯來對資料的操作進行嚴格的控制
目的是為了隔離複雜度,例如ATM程式的取款功能,該功能有很多其他功能組成
property
property就是將方法偽裝成資料
property就是將方法偽裝成資料
BMI例項:
有時候很多資料需要經過計算才可以獲得
但是這些資料給我們的感覺應該屬於資料而不是功能
BMI指數>>>:應該屬於人的資料而不是人的功能
class Person(object):
def __init__(self, name, height, weight):
self.__name = name
self.height = height
self.weight = weight
@property
def BMI(self):
return '%s的BMI指數是:%s' % (self.__name, self.weight / (self.height ** 2))
p1 = Person('tuzi', 1.79, 72)
print(p1.BMI)
# tuzi的BMI指數是:22.47120876377142
面向物件三大特性之多型
什麼是多型?
一種事物的多種形態
eg:水 固態 液態 氣態
動物 貓、豬、狗
多型性
class Animal(object):
def speak(self):
pass
class Cat(Animal):
def speak(self):
print('喵喵喵')
class Dog(Animal):
def speak(self):
print('汪汪汪')
class chicken(Animal):
def speak(self):
print('咯咯噠咯咯噠')
上述場景下,不僅僅體現了事物的多型性,但是雖然形態不同,但是動作是一樣的,所以可以呼叫相同的方法(speak)這一個相同的方法,這樣便於管理
c1 = Cat()
d1 = Dog()
p1 = Pig()
c1.speak()
d1.speak()
p1.speak()
面向物件的多型性其實在很早之前就已經接觸過了
eg:
s1 = 'hello world'
l1 = [1, 2, 3, 4]
d1 = {'name': 'jason', 'pwd': 123}
print(len(s1))
print(len(l1))
print(len(d1))
"""
多型性的好處在於增強了程式的靈活性和可擴充套件性,比如通過繼承Animal類建立了一個新的類,例項化得到的物件obj,可以使用相同的方式使用obj.speak()
面向物件的多型性也需要python程式設計師自己去遵守
雖然python推崇的是自由 但是也提供了強制性的措施來實現多型性
不推薦使用
"""
import abc
# 指定metaclass屬性將類設定為抽象類,抽象類本身只是用來約束子類的,不能被例項化
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod # 該裝飾器限制子類必須定義有一個名為talk的方法
def talk(self): # 抽象方法中無需實現具體的功能
pass
class Person(Animal): # 但凡繼承Animal的子類都必須遵循Animal規定的標準
def talk(self):
pass
p1=Person() # 若子類中沒有一個名為talk的方法則會丟擲異常TypeError,無法例項化
鴨子型別
由多型性衍生出一個鴨子型別理論
只要你看著像鴨子 走路像鴨子 說話像鴨子 那麼你就是鴨子!!!
案例
"""
在linux系統中有一句話>>>:一切皆檔案!!!
記憶體可以存取資料
硬碟可以存取資料
...
那麼多有人都是檔案
"""
class Memory(object):
def read(self):
pass
def write(self):
pass
class Disk(object):
def read(self):
pass
def write(self):
pass
類裡面有很多操作或者方式是一樣的,這樣的話以後操作起來會比較方便
# 得到記憶體或者硬碟物件之後 只要想讀取資料就呼叫read 想寫入資料就呼叫write 不需要考慮具體的物件是誰
面向物件之反射
反射
什麼是反射
專業解釋:指程式可以訪問、檢測和修改本身狀態或者行為的一種能力
大白話:其實就是通過字串來操作物件的資料和功能
反射需要掌握的四個方法
hasattr():判斷物件是否含有字串對應的資料或者功能
getattr():根據字串獲取對應的變數名或者函式名
setattr():根據字串給物件設定鍵值對(名稱空間中的名字)
delattr():根據字串刪除物件對應的鍵值對(名稱空間中的名字)
反射實際的應用
setattr(Student,'level','貴族學校')
print(Student.__dict__
def index():
pass
obj = Student()
setattr(obj, '血量', 10000)
setattr(obj, '功能', index)
print(obj.__dict__)
delattr(obj, '功能')
print(obj.__dict__)
什麼時候用反射
"""
什麼時候使用反射 可以記固定的口訣
以後只要在業務中看到關鍵字
物件 和 字串(使用者輸入、自定義、指定) 那麼肯定用反射
"""
import settings
dir(settings)
getattr(settings,'NAME')
class FtpServer:
def serve_forever(self):
while True:
inp = input('請輸入你的指令')
cmd,file = inp.split()
if hasattr(self,cmd):
func = getattr(self,cmd)
func(file)
def get(self,file):
print("正在下載%s"%file)
def put(self,file):
print('正在上傳%s'%file)
obj = FtpServer()
obj.serve_forever()