1.前戲
import datetime import json d = { 't1':datetime.datetime.today(), 't2':datetime.date.today() } res = json.dumps(d) print(res) ''' TypeError: Object of type 'datetime' is not JSON serializable '''
(1)此處代碼會報錯,無法正常序列化,原因是json序列化python數據類型是有限制的,並不適用於所有類型。
(2)利用json.JSONEncoder查看json序列化可以適用數據類型
(3)上述json存儲的為時間類型數據,所以不會被序列化。即將要被序列化的數據,裡裡外外都必須要保證是上述類型才行。
2.引出
針對上述不能被序列化的數據類型,給出下列解決辦法。
(1)解決方式一:
手動將不符合數據類型轉成符合要求的。import datetime import json d = { 't1':str(datetime.datetime.today()), 't2':str(datetime.date.today()) } res = json.dumps(d) print(res) ''' {"t1": "2022-07-28 15:48:31.269905", "t2": "2022-07-28"} '''
(2)解決方式二:
利用派生方法。查看dumps方法後得出:
class JSONEncoder: pass dumps(obj,cls=None): if cls == None: cls = JSONEncoder return cls(...) # JSONEncoder()
(1)查看JSONEncoder源碼發現序列化報錯是有default方法觸發的
raise TypeError(f'Object of type { o.__class__.__name__} ' f'is not JSON serializable')
(2)我們如果想要避免報錯 那麼肯定需要對default方法做修改(派生)
import datetime import json d = { 't1':datetime.datetime.today(), 't2':datetime.date.today() } class MyJsonEncode(json.JSONEncoder): def default(self, o): '''o就是json即將要序列化的數據''' if isinstance(o, datetime.datetime): return o.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(o, datetime.date): return o.strftime('%Y-%m-%d') # 如果是可以序列化的類型 那麼不做任何處理 直接讓它序列化即可 return super().default(o) res = json.dumps(d, cls=MyJsonEncode) print(res) json.dumps(d, cls=MyJsonEncode)
1.封裝的概念
封裝其實就是將數據或者功能隱藏起來;隱藏的目的不是讓用戶無法使用,而是給這些隱藏的數據開設特定的接口,讓用戶使用接口才可以去使用,我們在接口中添加一些額外的操作。
2.封裝隱藏特性
(1)在類定義階段使用雙下劃線開頭的名字都是隱藏屬性。
後續類和對象都無法直接獲取
(2)在python中不會真正的限制任何代碼。
隱藏的屬性如果真的需要訪問,也可以經過變形處理。不過這樣就失去了隱藏的意義!!!
3.封裝實例——代碼展示
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) print(stu1._Student__name) ''' jason ''' # 修改名字方法: stu1.set_info('kevin',20) print(stu1._Student__name) ''' kevin'''
4.代碼封裝之君子協定
我們在編寫python很多時候都是大家墨守成規的東西,不需要真正的限制(君子協定):class A: _school = '清華大學' def _choice_course(self): pass
1.偽裝的含義
可以簡單地理解為將方法偽裝成數據。數據只需要點名字:
obj.name方法至少還要加括號:
obj.func()
偽裝之後可以將func方法偽裝成數據:obj.func
2. @property主要功能作用
具體案例代碼展示:(1)# 沒有加裝飾器@property之前————p1.BMI() #加括號調用
class Person: def __init__(self, name, weight, height): self.name = name self.weight = weight self.height = height def BMI(self): return self.weight / (self.height ** 2) # 沒有加裝飾器@property之前 p1 = Person('jason',57,1.73) res = p1.BMI() # 加括號調用 print(res) ''' 19.045073340238563''' """BMI雖然需要計算獲得 但是更像是人的數據"""
(2)# 添加裝飾器@property之後————p1.BMI #直接調用
class Person: def __init__(self, name, weight, height): self.name = name self.weight = weight self.height = height @property def BMI(self): return self.weight / (self.height ** 2) # 添加裝飾器@property之後 p1 = Person('jason', 78, 1.83) print(p1.BMI) # 23.291229956104985 print(p1.name) # jason
3.知識點的加深之偽裝的徹底(了解)
需求:增加了用戶修改和刪除裝飾器class Foo: def __init__(self, val): self.__NAME = val # 將屬性隱藏起來 @property def name(self): return self.__NAME @name.setter def name(self, value): if not isinstance(value, str): # 在設定值之前進行類型檢查 raise TypeError('%s must be str' % value) self.__NAME = value # 通過類型檢查後,將值value存放到真實的位置self.__NAME @name.deleter def name(self): raise PermissionError('Can not delete') obj = Foo('jason') print(obj.name) # jason obj.name = 'kevin' print(obj.name) # kevin del obj.name # PermissionError: Can not delete
1.多態的字面含義
多態:一種事物的多種形態
水:液態 氣態 固態
動物:人 狗 貓 豬
2.具體實例代碼展示
(1)案例一:前戲之動物叫聲單獨方法調用:
class Animal(object): def spark(self): pass class Cat(Animal): def miao(self): print('喵喵喵') class Dog(Animal): def wang(self): print('汪汪汪') # c1 = Cat() d1 = Dog() c1.miao() # 喵喵喵 d1.wang() # 汪汪汪 """ 一種事物有多種形態,但是相同的功能應該有相同的名字; 這樣的話以後我們無論拿到具體的動物,都不需要知道到底是哪種動物,>直接調用相同的功能即可。 """
引出之不同動物叫聲用一個方法(spark)調用:
""" eg: 無論是雞鴨狗豬,只要叫就調用固定的屬於叫的功能!!! """ class Animal(object): def spark(self): pass class Cat(Animal): def spark(self): print('喵喵喵') class Dog(Animal): def spark(self): print('汪汪汪') c1.spark() # 喵喵喵 d1.spark() # 汪汪汪
(2)案例二:
不論是元組,列表還是字典,統計長度都是len方法調用。
l1 = [11, 22, 33, 44] d1 = { 'name': 'jason', 'pwd': 123, 'hobby': 'raed'} t1 = (11, 22, 33, 44) print(len(l1)) print(len(d1)) print(len(t1))
3.多態性的概念
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 def run(self): pass obj = Person()
4.鴨子類型
大白話解釋:只要你長得像鴨子,走路像鴨子,說話像鴨子,那麼你就是鴨子。class Teacher: def run(self):pass def eat(self):pass class Student: def run(self):pass def eat(self):pass
5.多態不同系統中解釋(鴨子類型推導)
(1)linux系統:一切皆文件
只要你能讀數據 能寫數據 那麼你就是文件
內存
硬盤class Txt: # Txt類有兩個與文件類型同名的方法,即read和write def read(self): pass def write(self): pass class Disk: # Disk類也有兩個與文件類型同名的方法:read和write def read(self): pass def write(self): pass class Memory: # Memory類也有兩個與文件類型同名的方法:read和write def read(self): pass def write(self): pass
(2)python:一切皆對象
只要你有數據 有功能 那麼你就是對象
文件名 文件對象
模塊名 模塊對象
1.反射的含義
通過字符串來操作對象的數據或方法
2.反射四個方法:
hasattr():判斷對象是否含有某個字符串對應的屬性
getattr():獲取對象字符串對應的屬性
setattr():根據字符串給對象設置屬性
delattr():根據字符串給對象刪除屬性
3. 反射實例代碼展示
class Student: school = '清華大學' def choice_course(self): print('選課') stu = Student() # 需求:判斷用戶提供的名字在不在對象可以使用的范圍內 # 方式1:利用異常處理(過於繁瑣) # try: # if stu.school: # print(f"True{stu.school}") # except Exception: # print("沒有屬性") """ 變量名school 與字符串school 區別大不大 stu.school stu.'school' 兩者雖然只差了引號 但是本質是完全不一樣的 """ # 方式2:獲取用戶輸入的名字 然後判斷該名字對象有沒有 # while True: # target_name = input('請輸入您想要核查的名字>>>:').strip() # '''上面的異常更加不好實現 需要用反射''' # # print(hasattr(stu, target_name)) # # print(getattr(stu, target_name)) # if hasattr(stu, target_name): # # print(getattr(stu, target_name)) # res = getattr(stu, target_name) # if callable(res): # print('拿到的名字是一個函數', res()) # else: # print('拿到的名字是一個數據', res) # else: # print('不好意思 您想要查找的名字 對象沒有') print(stu.__dict__) stu.name = 'jason' stu.age = 18 print(stu.__dict__) setattr(stu, 'gender', 'male') setattr(stu, 'hobby', 'read') print(stu.__dict__) del stu.name print(stu.__dict__) delattr(stu, 'age') print(stu.__dict__)
4.反射用法
需求裡面只要看到…字符串或者…對象那麼肯定需要使用反射!!!
5.反射實戰案例
class FtpServer: def serve_forever(self): while True: inp = input('input your cmd>>: ').strip() cmd, file = inp.split() if hasattr(self, cmd): # 根據用戶輸入的cmd,判斷對象self有無對應的方法屬性 func = getattr(self, cmd) # 根據字符串cmd,獲取對象self對應的方法屬性 func(file) def get(self, file): print('Downloading %s...' % file) def put(self, file): print('Uploading %s...' % file) obj = FtpServer() obj.serve_forever()