文章目錄
- 一、多態
- 1、什么是多態
- 2、多態小實驗
- 二、封裝
- 1、什么是封裝
- 2、內部屬性的約定
- 三、反射
- 1、什么是反射
- 2、四個實現自省的函數
- (1)hasattr(object,name)
- (2)getattr(object,name,default=None)
- (3)setattr(object,name,value)
- (4)delattr(object,name)
- 3、反射的用途
- 4、動態導入模塊
- 四、attr內置方法
- 1、__getattr__()
- 2、__delattr__()
- 3、__setattr__()
- 五、小實驗1:包裝標準類型
- 六、小實驗2:組合方式完成授權,改寫文件處理函數
一、多態
1、什么是多態
多態是指對象通過他們共同的屬性和方法來操作及訪問,而不需要考慮他們具體的類。
s = "abc"
print(s.__len__()) # 3,等同len(s)l = [1, 3]
print(l.__len__()) # 2,等同len(l)
多態體現在由同一個類實例化出多個對象,這些對象執行相同的方法時,執行的過程和結果是不一樣的。
class H2O:def __init__(self, name, tem):self.name = nameself.tem = temdef turn(self):if self.tem > 100:print("%s 變成了水蒸氣" % self.name)elif self.tem < 0:print("%s 變成了冰" % self.name)else:print("%s 變成了水" % self.name)class Steam(H2O):pass
class Water(H2O):pass
class Ice(H2O):passs = Steam("s", 1000)
w = Water("w", 50)
i = Ice("i", -10)s.turn() # s 變成了水蒸氣
w.turn() # w 變成了水
i.turn() # i 變成了冰
2、多態小實驗
模擬 len() 函數,對上述turn方法,做成函數形式。
# 接上述實例化代碼后,補充如下代碼
def turn(obj):obj.turn()turn(s) # s 變成了水蒸氣
turn(w) # w 變成了水
turn(i) # i 變成了冰
二、封裝
1、什么是封裝
(1)裝,即把一些屬性裝到一個容器中。封,即為隱藏。
(2)類就是一種容器,這本身就是一種封裝。
(3)類中定義私有的屬性,只有類的內部可以使用,外部無法訪問。
(4)封裝明確區分內外,內部的實現邏輯,外部無法知曉,并且為封裝到內部的邏輯提供一個訪問接口給外部使用。
2、內部屬性的約定
python并沒有嚴格限制外部訪問內部屬性,但把單下劃線和雙下劃線開頭的屬性約定為內部屬性。
class People:_age = 18__sex = "f"def __init__(self):passdef info(self):print("age %s,sex %s" %(self._age, self.__sex))
p1 = People()
print(People._age) # 18 但下劃線開頭屬性,外部可以直接訪問
print(People._People__sex) # f 雙下劃線開頭屬性,會在屬性字典中重命名為_類__屬性
p1.info() # age 18,sex f 內部可以調用它們
三、反射
1、什么是反射
反射主要是指程序可以訪問、檢測、和修改它本身狀態或行為的一種能力(自省)。
2、四個實現自省的函數
以下四個函數適用于類和對象。
(1)hasattr(object,name)
?判斷name是否在object中。
(2)getattr(object,name,default=None)
? 相當于執行object.name
(3)setattr(object,name,value)
? 設置object的屬性
(4)delattr(object,name)
?刪除object中的name屬性
class People:age = 18sex = "f"def __init__(self):self.age = self.agedef info(self):print("age %s,sex %s" % (self.age, self.sex))p1 = People()print(hasattr(p1, "age")) # True 相當于判斷p1.age是否可以被調用
getattr(p1, "info")() # age 18,sex f 相當于調用p1.info
# getattr(p1, "info1")() # 沒有info1,則報錯
print(getattr(p1, "info1", 10)) # 10 沒有不報錯,返回默認值setattr(p1,"func",lambda x:x*2)
print(p1.func(3)) # 6
print(p1.__dict__) # {'age': 18, 'func': <function <lambda> at 0x000001623A680160>}
delattr(p1,"age") # 刪除age屬性
print(p1.__dict__) # {'func': <function <lambda> at 0x000001623A680160>}
3、反射的用途
可以事先定義接口,接口只有在被完成后才會真正執行,這實現了即插即用。
prog1代碼:
class Ftp:def __init__(self):passdef put(self):print("執行put方法")
調用程序代碼:
from prog1 import Ftp
f1 = Ftp()if hasattr(f1,"put"):func_get = getattr(f1,"put")func_get()
else:print("執行其他邏輯")
4、動態導入模塊
動態導入模塊就是基于反射實現的。
t.py代碼:
def test1():print("I am test1")def _test2():print("I am test2")
執行模塊代碼:
module_t = __import__("d1.t") # d1與執行模塊在同級目錄,t為d1的子文件
print(module_t) # <module 'd1' (namespace)>
module_t.t.test1() # I am test1
from d1.t import *
_test2() #報錯
from d1.t import test1,_test2
_test2() #不報錯
from d1 import t
t._test2() # 不報錯
import importlib
m = importlib.import_module("d1.t")
m._test2() # 不報錯
四、attr內置方法
在不自定義這些內置方法時,程序會執行其自身的對應方法。
1、getattr()
在屬性不存在時,會自動觸發自定義的__getattr__()。屬性存在時,不執行它,而是執行其自身的方法。
class Foo:def __init__(self,y):self.y = ydef __getattr__(self, item):print("執行我")f1 = Foo(10)
print(f1.y) # 10
print(getattr(f1,"y")) # 10
f1.aa # 執行我
2、delattr()
執行 del 對象.屬性 時,會觸發 __delattr__()
class Foo:x = 1def __init__(self,y):self.y = ydef __delattr__(self, item):print("執行我")self.__dict__.pop(item)f1 = Foo(10)
print(f1.__dict__) # {'y': 10}
del f1.y # 執行我
print(f1.__dict__) # {}
3、setattr()
在執行對象.屬性=value時,觸發 __setattr__()
class Foo:x = 1def __init__(self,y):passdef __setattr__(self, key, value):print("執行我")self.__dict__[key] = valuef1 = Foo(10)
print(f1.__dict__) # {}
f1.y = 11 # 執行我
print(f1.__dict__) # {'y': 11}
五、小實驗1:包裝標準類型
重寫列表類型:只能向列表中添加字符串元素;刪除元素后,要返回該元素值。
class List(list):def append(self, obj):if type(obj) is str:super().append(obj)else:print("必須是字符串")l = List("ab")
print(l) # ['a', 'b']
l.append(1) # 必須是字符串
print(l) # ['a', 'b']
l.append("c")
print(l) # ['a', 'b', 'c']
六、小實驗2:組合方式完成授權,改寫文件處理函數
授權是包裝的一個特性。包裝一個類型通常是對已存在的類型的一些定制,這種做法可以新建,修改或刪除原有產品的功能,其他的則保持原樣。授權的過程是所有更新的功能都是由新類的某部分來處理,但已存在的功能就授權給對象為默認屬性。
實驗內容:寫入文件內容加時間。其他文件處理函數的功能不變。
import time
class FileHandle:def __init__(self,filename,mode="r",encoding="utf-8"):self.f = open(filename,mode,encoding=encoding)def write(self,content):t = time.strftime("%F %X")self.f.write("%s %s" %(t,content))def __getattr__(self, item):return getattr(self.f,item)f1 = FileHandle("a.txt","w+")
f1.write("內存空間不足!\n")
f1.write("磁盤空間不足!")
f1.seek(0)
print(f1.read())
f1.close()'''a.txt內容
2024-02-22 15:57:05 內存空間不足!
2024-02-22 15:57:05 磁盤空間不足!
'''