面向對象進階

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)
getattr,hasattr,setattr,delattr

 

 

雙下方法函數


先了解這種編程思惟,之後有機會能夠來細究,雙下方法用得好,有時候能夠大大簡化代碼,及調高編程效率學習

__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,就會報錯
雙下方法-str,repr,del,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))
雙下方法hash,eq

 

__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
雙下方法-new-面試考題
#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__)
雙下方法-item

 

咱們在使用內置函數的時候,不少時候都是調用內置雙下方法

內置函數  內置模塊  內置數據類型 其實和雙下方法有着千絲萬縷的關係:可是隻能在之後學習工做中慢慢積累,

咱們來看看下面這兩個練習:

 

練習一:

在這個紙牌遊戲中,利用雙下方法,就定義了紙牌遊戲,不用本身寫方法

同時瞭解到使用 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)
去重-set依賴eq和hash
相關文章
相關標籤/搜索