1.反射python
2.雙下方法面試
1 什麼是反射json
反射的概念是由Smith在1982年首次提出的,主要是指程序能夠訪問、檢測和修改它自己狀態或行爲的一種能力(自省)。這一律唸的提出很快引起了計算機科學領域關於應用反射性的研究。它首先被程序語言的設計領域所採用,並在Lisp和麪向對象方面取得了成績。設計模式
2 python面向對象中的反射:經過字符串的形式操做對象相關的屬性。python中的一切事物都是對象(均可以使用反射)app
四個能夠實現自省的函數dom
下列方法適用於類和對象(一切皆對象,類自己也是一個對象)ide
class Teacher: dic = {'查看老師信息':'show_teacher','查看學生信息':'show_studend'} def show_teacher(self): print('show teacher') def show_studend(self): print('show_studend') alex = Teacher() for k in Teacher.dic: print(k) key = input('you want: ') if hasattr(alex,Teacher.dic[key]): ret = getattr(alex,Teacher.dic[key]) #獲取到內存地址 ret() #alex.show_studend()
#最重要的兩個 hasattr getattr # class B:pass # class A(B):pass # a = A() # print(isinstance(a,A)) # print(isinstance('name',str)) # print(issubclass(A,B)) # # getattr() class A: price = 20 def fuc(self): print('in func') @classmethod def func2(cls): print('method of class') a = A() a.name = 'gkx' # 變量名 = input('>>> ') # print(getattr(a,變量名)) #print(a.__dict__[變量名]) #如下用 dict投機倒把而已 #A.__dict__[變量名](a) # print(getattr(A,'price')) # if hasattr(A,'func2'): # getattr(A,'func2')() #只要是 xx.yy 帶點的,均可以反射 year = 2018 def wahaha(): print('wahahahaha') import sys print(__name__) #當__name__ 在本py運行的時候等於__main__ ,當被導入使用的時候,__name__等於 py文件名 print(sys.modules) print(sys.modules[__name__]) #獲取本py文件的模塊地址,而後就能夠反射了, getattr(sys.modules[__name__],'wahaha')() #要用__name__ 此處不能用'__main__'這樣這段代碼就寫死了,其餘地方若是導入這個py,用不了這段代碼 #只要是 xx.yy 帶點的,均可以反射 #能夠反射模塊 import time # inp = input('>>> ') #輸入time # print(getattr(time,inp)()) # inp2 = input('>>> ') #輸入localtime # ret = getattr(time,inp2)() # print(ret) # inp3 = input('>>> ') #輸入asctime # print(getattr(time,inp3)(ret)) #模塊中的類也能夠被咱們拿到 import for_import print(getattr(for_import,'C').__dict__) c = getattr(for_import,'C')() c.name = 'gkx' print(c.__dict__) #不重要的 setattr 和 delattr # setattr 設置,修改屬性 class A:pass a = A() setattr(A,'name','alex') setattr(a,'name','gkx') print(A.name) print(a.name) #對象裏有name,我就先找 name,不找類屬性 #delattr delattr(a,'name') #對象裏的name被刪除了,就去找類裏的,輸出爲 alex print(a.name)
先了解這種編程思惟,之後有機會能夠來細究,雙下方法用得好,有時候能夠大大簡化代碼,及調高編程效率學習
__str__ __repr__ __del__ __call__
class B:pass class A(B): def __init__(self,name): self.name = name # def __str__(self): #這個方法必定要return一個字符串 # return "A 裏面的 雙下str" def __repr__(self): #這個方法必定要return一個字符串 return str(self.__dict__) a = A('gkx') print(a) #沒當你打印對象的時候,就是調用這個對象的雙下str方法(若無,就找父類object) a.__str__ print(str(a)) #此時調用的是 類A 父類 object裏面的 __str__,它返回的是一個內存地址。 #如何證實呢? #此時若是 類A裏有個雙下方法__str__,它就會優先調用 類A裏的 print('%s----%s'%('A',a)) # %s print(a) str(a) 都是在調用 a.__str__ #注意,此處針對的都是 class A。 print(str(a)) #調用的都是 雙下repr,若是類中沒有repr,就找父類要,父類沒有繼續找祖父類 object要 print('%r'%a) #!!!!!!特大八卦 # repr是str的備胎,當類A未定義雙下str,可是類A中定義了 雙下repr,此時調用str(a)就會調用類A中的雙下 repr #可是反過來,若是類A中只有str,沒有repr,則repr仍是隻會去找父類要雙下repr #也就是說,str會去找類中的repr,repr只能本身找object #沒str會找repr,沒repr,只能回找boject #老師總結 # print(obj)/'%s'%obj/str(obj)的時候,其實是內部調用了obj.__str__方法,若是str方法有,那麼他返回的一定是一個字符串 # 若是沒有__str__方法,會先找本類中的__repr__方法,再沒有再找父類中的__str__。 # repr(),只會找__repr__,若是沒有找父類的 #並非全部內置方法都在object中,好比: #__len__就沒有 class Classes: def __init__(self,name): self.name = name self.student = [] def __len__(self): #當去掉這個方法,下面再調用 len 會報錯! return len(self.student) python_s9 = Classes('py_s9') python_s9.student.append('gkx') print(len(python_s9)) #__del__ # class A: # def __del__(self): # 析構函數: 在刪除一個對象以前進行一些收尾工做 # self.f.close() # a = A() # a.f = open() # 打開文件 第一 在操做系統中打開了一個文件 拿到了文件操做符存在了內存中 # del a # a.f 拿到了文件操做符消失在了內存中 # del a # del 既執行了這個方法,又刪除了變量 # 引用計數 # __call__ class A: def __init__(self,name): self.name = name def __call__(self): ''' 打印這個對象中的全部屬性 :return: ''' for k in self.__dict__: print(k,self.__dict__[k]) a = A('alex')() #一個對象加上括號,就是調用了 雙下call方法,若是類中沒雙下call,就會報錯
python2中是調用 __unicode__
__hash__ __eq__
# __eq__方法 class A: def __init__(self,name): self.name = name def __eq__(self, other): if self.__dict__ == other.__dict__: return True else: return False a = A('gkx') a2 = A('gkx') print(a == a2) ##若是沒有eq方法,是比較內存地址,會返回False # __hash__ class B: def __init__(self,name,age): self.name = name self.age = age def __hash__(self): return hash(self.name+self.age) #經過雙下哈希,控制當屬性同樣哈希值是同樣的 b = B('gkx','11') b1 = B('gkx','11') print(hash(b)) #在一個程序執行過程當中,某個變量的哈希值一直不會改變 print(hash(b)) print(hash(b1))
__new__
# __new__ 構造方法,建立一個對象。在實例化的時候,就調用了object裏的__new__建立了self # __init__ 初始化方法 class A: def __init__(self): self.x = 1 print('in the __init__ ') def __new__(cls, *args, **kwargs): print('in the __new__ ') return object.__new__(A,*args, **kwargs) a = A() #先打印 in the new 再打印 in the init
#23中設計模式 #單例模式 # 一個類 始終 只有 一個 實例 # 當你第一次實例化這個類的時候 就建立一個實例化的對象 # 當你以後再來實例化的時候 就用以前建立的對象 class B: __isinstance = False def __init__(self,name,age): self.name = name self.age = age def __new__(cls, *args, **kwargs): if cls.__isinstance: return cls.__isinstance cls.__isinstance = object.__new__(cls) return cls.__isinstance aa = B('gkx',11) aa.cloth = '1111111' bb = B('ww',22) print(aa,bb) #內存空間是如出一轍的 print(aa.name) print(bb.name) #因此name的值根據後面一個實例化而得 print(bb.cloth)
__getitem__ __setitem__ __delitem__
class Foo: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def __getitem__(self, item): if hasattr(self,item): #判斷self,這個對象裏是否有 item這個屬性 print(self.__dict__[item]) def __setitem__(self, key, value):#相似字典的新增 self.__dict__[key] = value #print(key,value) def __delitem__(self, key): del self.__dict__[key] f = Foo('gkx',12,'male') f['name'] #對於 雙下getitem,當 obj[item]這種格式的時候,中括號裏的值,自動傳入方法內的參數 item,語法就是這麼規定的 f['hobby'] = 'ww' #相似字典的新增,語法規定,hobby傳給key ,ww傳給value print(f.__dict__) # del f.hobby #原生刪除方法 del f['hobby'] print(f.__dict__)
咱們在使用內置函數的時候,不少時候都是調用內置雙下方法
內置函數 內置模塊 內置數據類型 其實和雙下方法有着千絲萬縷的關係:可是隻能在之後學習工做中慢慢積累,
咱們來看看下面這兩個練習:
練習一:
在這個紙牌遊戲中,利用雙下方法,就定義了紙牌遊戲,不用本身寫方法
同時瞭解到使用 random模塊的時候,choice須要用到__len__獲取長度, shuffle須要用到 __setitem__ 亂序的時候須要獲取到 index
import json from collections import namedtuple Card = namedtuple('card',['rank','suit']) ranks = [str(n) for n in range(2,11)] + list('JQKA') suits = ['紅心','黑桃','梅花','方塊'] class Franchdeck: def __init__(self): self._card = [Card(rank,suit) for rank in ranks # for suit in suits: for suit in suits] #for rank in ranks: #在推導式中寫後面的放前面 def __getitem__(self, item): # item就是你在類外想調用的index,在字典中就是key return self._card[item] def __len__(self): #在導入random模塊的時候,使用choice和shuffle須要用到雙下len return len(self._card) def __setitem__(self, key, value): #亂序的時候須要setitem,是由於亂序須要用到索引,把索引打亂,可是對應的值不能錯 self._card[key] = value def __str__(self): return json.dumps(self._card,ensure_ascii=False) # ensure_ascii=False 取消中文轉義 #return str(self._card) # 這樣直接打印 print(deck)就不是內存地址了 str(deck) %s deck = Franchdeck() print(deck[0]) import random print(random.choice(deck)) random.shuffle(deck) print(deck[:5]) print(deck) #能夠獲取整個列表的值,上面的切片就是從這裏切的 #如下沒用,本身瞎寫的 # c1 = Card(2,'紅心') # print(c1) # print(c1.rank) # print(getattr(c1,'rank')) # print(c1[1]) # # lst = [] # dic1 = {} # ranks = [str(n) for n in range(2,11)] + list('JQKA') # for suit in ['紅心','黑桃','方塊','梅花']: # for rank in ranks: # lst.append(Card(rank,suit)) # print(lst) # print(dic1)
練習二:
set集合去重,依賴__eq__ 以及 __hash__
class A: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def __eq__(self, other): if self.name == other.name and self.sex == other.sex: return True return False def __hash__(self): return hash(self.name+self.sex) # def __str__(self): # return str(self.__dict__) a = A('egg',11,'男') a2 = A('egg',12,'男') print(set([a,a2])) p_lst = [] for i in range(84): p_lst.append(A('egg',i,'男')) print(p_lst) print(set(p_lst)) # for i in p_lst: #關於讀取內存地址內容,若是是函數就直接加括號執行,把內存地址等價於變量名便可 # print(i.name)