標籤:字典 size module setattr 建立對象 反射 layout oldboy not
isinstance(obj,cls)檢查是否obj是否是類 cls 的對象
issubclass(sub, super)檢查sub類是否是 super 類的衍生類別
反射
反射的概念是由Smith在1982年首次提出的,主要是指程式可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。
hasattr(object,name)判斷object中有沒有一個name字串對應的方法或屬性
getattr(object, name, default=None),擷取屬性
setattr(x, y, v),建立屬性
delattr(x, y),刪除屬性
為什麼用反射之反射的好處
好處一:實現可插拔機制
有倆程式員,一個lili,一個是egon,lili在寫程式的時候需要用到egon所寫的類,但是egon去跟女朋友度蜜月去了,還沒有完成他寫的類,lili想到了反射,使用了反射機制lili可以繼續完成自己的代碼,等egon度蜜月回來後再繼續完成類的定義並且去實現lili想要的功能。
總之反射的好處就是,可以事先定義好介面,介面只有在被完成後才會真正執行,這實現了隨插即用,這其實是一種‘後期綁定’,什麼意思?即你可以事先把主要的邏輯寫好(只定義介面),然後後期再去實現介面的功能
好處二:動態匯入模組(基於反射當前模組成員)
類屬性相關方法__setattr__,__delattr__,__getattr__
class Foo: x=1 def __init__(self,y): self.y=y def __getattr__(self, item): print(‘----> from getattr:你找的屬性不存在‘) def __setattr__(self, key, value): print(‘----> from setattr‘) # self.key=value #這就無限遞迴了,你好好想想 # self.__dict__[key]=value #應該使用它 def __delattr__(self, item): print(‘----> from delattr‘) # del self.item #無限遞迴了 self.__dict__.pop(item)#__setattr__添加/修改屬性會觸發它的執行f1=Foo(10)print(f1.__dict__) # 因為你重寫了__setattr__,凡是賦值操作都會觸發它的運行,你啥都沒寫,就是根本沒賦值,除非你直接操作屬性字典,否則永遠無法賦值f1.z=3print(f1.__dict__)#__delattr__刪除屬性的時候會觸發f1.__dict__[‘a‘]=3#我們可以直接修改屬性字典,來完成添加/修改屬性的操作del f1.aprint(f1.__dict__)#__getattr__只有在使用點調用屬性且屬性不存在的時候才會觸發f1.xxxxxx三者的用法示範
一個靜態屬性property本質就是實現了get,set,delete三種方法
class Foo: @property def AAA(self): print(‘get的時候運行我啊‘) @AAA.setter def AAA(self,value): print(‘set的時候運行我啊‘) @AAA.deleter def AAA(self): print(‘delete的時候運行我啊‘)#只有在屬性AAA定義property後才能定義AAA.setter,AAA.deleterf1=Foo()f1.AAAf1.AAA=‘aaa‘del f1.AAA
應用
class Goods: 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_priceobj = Goods()obj.price # 擷取商品價格obj.price = 200 # 修改商品原價print(obj.price)del obj.price # 刪除商品原價案例一
執行個體項相關方法__setitem__,__getitem,__delitem__
class Foo: def __init__(self,name): self.name=name def __getitem__(self, item): print(self.__dict__[item]) def __setitem__(self, key, value): self.__dict__[key]=value def __delitem__(self, key): print(‘del obj[key]時,我執行‘) self.__dict__.pop(key) def __delattr__(self, item): print(‘del obj.key時,我執行‘) self.__dict__.pop(item)f1=Foo(‘sb‘)f1[‘age‘]=18f1[‘age1‘]=19del f1.age1del f1[‘age‘]f1[‘name‘]=‘alex‘print(f1.__dict__)
__str__,__repr__,__format__
改變對象的字串顯示__str__,__repr__
自定製格式化字串__format__
#_*_coding:utf-8_*___author__ = ‘Linhaifeng‘format_dict={ ‘nat‘:‘{obj.name}-{obj.addr}-{obj.type}‘,#學校名-學校地址-學校類型 ‘tna‘:‘{obj.type}:{obj.name}:{obj.addr}‘,#學校類型:學校名:學校地址 ‘tan‘:‘{obj.type}/{obj.addr}/{obj.name}‘,#學校類型/學校地址/學校名}class School: def __init__(self,name,addr,type): self.name=name self.addr=addr self.type=type def __repr__(self): return ‘School(%s,%s)‘ %(self.name,self.addr) def __str__(self): return ‘(%s,%s)‘ %(self.name,self.addr) def __format__(self, format_spec): # if format_spec if not format_spec or format_spec not in format_dict: format_spec=‘nat‘ fmt=format_dict[format_spec] return fmt.format(obj=self)s1=School(‘oldboy1‘,‘北京‘,‘私立‘)print(‘from repr: ‘,repr(s1))print(‘from str: ‘,str(s1))print(s1)‘‘‘str函數或者print函數--->obj.__str__()repr或者互動式解譯器--->obj.__repr__()如果__str__沒有被定義,那麼就會使用__repr__來代替輸出注意:這倆方法的傳回值必須是字串,否則拋出異常‘‘‘print(format(s1,‘nat‘))print(format(s1,‘tna‘))print(format(s1,‘tan‘))print(format(s1,‘asfdasdffd‘))__doc__查看類的描述資訊
class Foo: ‘我是描述資訊‘ passprint(Foo.__doc__)
__module__ 表示當前操作的對象在那個模組
__class__ 表示當前操作的對象的類是什麼
from lib.aa import Cobj = C()print obj.__module__ # 輸出 lib.aa,即:輸出模組print obj.__class__ # 輸出 lib.aa.C,即:輸出類
__call__ 方法:對象後面加括弧,觸發執行。
註:構造方法的執行是由建立對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象後加括弧觸發的,即:對象() 或者 類()()
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print(‘__call__‘)obj = Foo() # 執行 __init__obj() # 執行 __call__
物件導向進階