python面向物件進階
阿新 • • 發佈:2020-08-13
類相關的內建函式
isinstance
內建函式
isinstance(obj,cls) 檢查obj是否是cls的物件
class C:pass
a = C()
print(isinstance(a,C)) 返回布林型別
issubclass
issubclass(sub,super)檢查sub是否是super的派生類
class B(C):
pass
print(issubclass(B,C)) 返回布林型別
反射
1 什麼是反射
反射的概念是由Smith在1982年首次提出的,主要是指程式可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。這一概念的提出很快引發了電腦科學領域關於應用反射性的研究。它首先被程式語言的設計領域所採用,並在Lisp和麵向物件方面取得了成績。
2 python面向物件中的反射:通過字串的形式操作物件相關的屬性。python中的一切事物都是物件(都可以使用反射)
四個可以實現自省的函式
下列方法適用於類和物件(一切皆物件,類本身也是一個物件)
四個方法:hasattr getattr setatte delattr
hasattr 和 getattr 組合使用
import mymodul # 是自定義模組
if hasattr(mymodul,'Modul_cls'): #判斷是否存在這個類名再執行後面的
print(getattr(mymodul,'Modul_cls')) # 獲取到一個類的物件
#<class 'mymodul.Modul_cls'>
class A:
def func(self):
print('in func')
a = A()
a.name = 'alex'
a.age = 63
A.func(a)
# 反射物件的屬性
ret = getattr(a,'age') # 通過變數名的字串形式取到的值
print(ret)
# 反射物件的方法
print(getattr(a,'func'))
# 反射類的方法
print(getattr(A,'func'))
反射模組的屬性
import mymodul
print(getattr(mymodul,'year'))
# 反射模組的方法
getattr(mymodul,'fangfa')() # 獲取到的是一個函式名加()就是呼叫# 內建模組也能用
# 反射自己模組中的變數和模組
def func():
print('自己模組名')
import sys
print(sys.modules['__main__']) # 這裡要使用__name__如被其他指令碼匯入後使用用__name才能生效此方法
im = input('>>>')
getattr(sys.modules[__name__],im)()
要反射的函式有引數
import time
time.strftime('%Y-%m-%d %H:%M:%S')
getattr(time,'strftime')('%Y-%m-%d %H:%M:%S')
def qqx():pass
import sys
print(sys.modules['__main__']) #__name__
setattr # 設定修改變數
class D:pass
a = D()
setattr(a,'name','classtor') # 往物件a中新增一個靜態屬性
print(a.name)
setattr(D,'name',123)
print(D.name) # 往類D 中新增靜態屬性
delattr 刪除屬性
delattr(a,'name') # 刪除了物件a屬性中的name 列印類中的屬性 123
print(a.name) # 123
delattr(D,'name')
print(a.name) # 刪除了類的name屬性再列印找不到會報錯
class Foo: f = '類的靜態變數' def __init__(self,name,age): self.name=name self.age=age def say_hi(self): print('hi,%s'%self.name) obj=Foo('egon',73) #檢測是否含有某屬性 print(hasattr(obj,'name')) print(hasattr(obj,'say_hi')) #獲取屬性 n=getattr(obj,'name') print(n) func=getattr(obj,'say_hi') func() print(getattr(obj,'aaaaaaaa','不存在啊')) #報錯 #設定屬性 setattr(obj,'sb',True) setattr(obj,'show_name',lambda self:self.name+'sb') print(obj.__dict__) print(obj.show_name(obj)) #刪除屬性 delattr(obj,'age') delattr(obj,'show_name') delattr(obj,'show_name111')#不存在,則報錯 print(obj.__dict__)四個方法的其他演示
class Foo(object): staticField = "old boy" def __init__(self): self.name = 'wupeiqi' def func(self): return 'func' @staticmethod def bar(): return 'bar' print getattr(Foo, 'staticField') print getattr(Foo, 'func') print getattr(Foo, 'bar')類也是物件
#!/usr/bin/env python # -*- coding:utf-8 -*- import sys def s1(): print 's1' def s2(): print 's2' this_module = sys.modules[__name__] hasattr(this_module, 's1') getattr(this_module, 's2')反射當前模組成員
#!/usr/bin/env python # -*- coding:utf-8 -*- def test(): print('from the test') #!/usr/bin/env python # -*- coding:utf-8 -*- """ 程式目錄: module_test.py index.py 當前檔案: index.py """ import module_test as obj #obj.test() print(hasattr(obj,'test')) getattr(obj,'test')()匯入其他模組,利用反射查詢該模組是否存在某個方法
__str__ 和 __reper__
改變物件的字串顯示__str__
__repr__ 原型畢露
自定製格式化字串__format__
class A:
# def __str__(self):
# return '執行我啦'
def __init__(self,name,age):
self.name = name
self.age = age
def __repr__(self):
return '執行我啦reper'
def fund(self):
print('執行我啦')
a = A('alex',98)
print(a) # 列印一個物件時,實際是執行物件中__str__方法,沒有返回記憶體地址
# <__main__.A object at 0x01E01DF0>
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(s1)
print('from repr: ',repr(s1))
print('from str: ',str(s1))
print(s1)
lst = [1,2,3,4,5] # 例項化列表類方法
print(lst) # 實際呼叫lst下的__str__方法 即obj物件
%s 和 %r
class B:
def __str__(self):
return 'str : class B'
def __repr__(self):
return 'repr : class B'
b=B()
print('%s'%b)
print('%r'%b)
小結:
雙下方法
內建的類方法和內建的函式之間有著千絲萬縷的聯絡
__str__
__repr__ 原型畢露
object 裡有一個__str__,一旦被呼叫,就返回呼叫這個方法的物件的記憶體地址
repr 是 str的備胎
str 不能做 repr 的備胎
print(obj)、%s 、str(obj) 的時候,實際上是內部呼叫了obj.__str__方法,如果str方法有,那麼返回的必定是一個字串,其他會報錯
如果沒有__str__方法,會先找本類中的__repr__方法,再沒有再找父類中的__str__,如沒有就會呼叫object中的__srt__方法會列印一個記憶體地址
repr() 只會找__repr__,如果沒有找父類的
item系列
__getitem__ 和 __setitem__和__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']=18
f1['age1']=19
print(f1.__dict__)
del f1.age #執行物件中__delitem__方法
print(f1.__dict__)
del f1['age1'] #物件中有__delattr__方法,可以使用此方式進行刪除
print(f1.__dict__)
f1['name']='alex'
print(f1.__dict__) #物件中有__getitem__方法,可以使用此方式進行刪除
__del__
析構方法,當物件在記憶體中被釋放時,自動觸發執行。
注:此方法一般無須定義,因為Python是一門高階語言,程式設計師在使用時無需關心記憶體的分配和釋放,因為此工作都是交給Python直譯器來執行,所以,解構函式的呼叫是由直譯器在進行垃圾回收時自動觸發執行的。
class A:
def __del__(self): # 解構函式
print('執行我啦')
a = A()
del a # 執行了__del__此方法,有把a這個物件給刪除了
print(a.__dict__) # 所以這裡列印是會報錯哦
__new__ 構造方法:建立一個物件
一個類始終只有一個例項
當你第一個次例項化這個類的時候,就建立一個例項化的物件
當你之後再來例項化的時候,就用之前建立的物件
單列模式
class A:
__instance = False
def __init__(self,name,age):
self.name= name
self.age = age
def __new__(cls, *args, **kwargs):
if cls.__instance:
return cls.__instance
cls.__instance = object.__new__(A) # cls 也可以寫這個
return cls.__instance
egnon nezha 完全相同可以使用 id() == is 檢測
egon = A('egon',38)
egon.cloth = '小花衣'
nezha = A('nezha',25)
print(nezha)
print(egon)
print(nezha.name)
print(egon.name)
print(egon == nezha) # True
print(egon is nezha) # True 對比記憶體地址
__call__
物件後面加括號,觸發執行。注:構造方法的執行是由建立物件觸發的,即:物件 = 類名() ;而對於 __call__ 方法的執行是由物件後加括號觸發的,即:物件() 或者 類()()
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 執行 __init__
obj() # 執行 __call__
with和__enter__,__exit__
with 語句
class A:
def __enter__(self):
print('before')
def __exit__(self, exc_type, exc_val, exc_tb):
print('after')
with A() as a:
print('123')
# before
# 123
# after
with 和檔案操作
# with 和檔案操作
class Myfile:
def __init__(self,path,mode='r',encoding = 'utf-8'):
self.path = path
self.mode = mode
self.encoding = encoding
def __enter__(self):
self.f = open(self.path, mode=self.mode, encoding=self.encoding)
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
with Myfile('file',mode='w') as f:
f.write('wahaha') # 在本目錄建立了file檔案並寫入了wahaha
with 和 pickle
import pickle
class MyPickledump:
def __init__(self,path):
self.path = path
def __enter__(self):
self.f = open(self.path, mode='ab')
return self
def dump(self,content):
pickle.dump(content,self.f)
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
class Mypickleload:
def __init__(self,path):
self.path = path
def __enter__(self):
self.f = open(self.path, mode='rb')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
def load(self):
return pickle.load(self.f)
def loaditer(self):
while True:
try:
yield self.load()
except EOFError:
break
# with MyPickledump('file') as f:
# f.dump({1,2,3,4}) #以ab模式把1/2/3/4寫入了file檔案內
with Mypickleload('file') as f:
for item in f.loaditer():
print(item)
with 和 pickle 和iter
import pickle
class MyPickledump:
def __init__(self,path):
self.path = path
def __enter__(self):
self.f = open(self.path, mode='ab')
return self
def dump(self,content):
pickle.dump(content,self.f)
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
class Mypickleload:
def __init__(self,path):
self.path = path
def __enter__(self):
self.f = open(self.path, mode='rb')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
def __iter__(self):
while True:
try:
yield pickle.load(self.f)
except EOFError:
break
# with MyPickledump('file') as f:
# f.dump({1,2,3,4})
with Mypickleload('file') as f:
for item in f:
print(item)
__len__
class A:
def __init__(self):
self.a = 1
self.b = 2
def __len__(self):
return len(self.__dict__)
a = A()
print(len(a)) #求物件的長度是,依賴物件內部的len發放
__hash__ 方法
class H:
def __init__(self,name,sex):
self.name = name
self.sex = sex
def __hash__(self):
return hash(self.name+self.sex)
a = H('egon','男')
b = H('egon','男')
print(hash(a)) # 608824368
print(hash(b)) # 608824368 兩個物件的HASH一致
#
100名字 和 性別相同,就認為是一個物件去重 你年齡不同
set 去重物件
class A:
def __init__(self,name,sex,age):
self.name = name
self.sex = sex
self.age = age
def __hash__(self):
sec = hash(self.name+ self.sex)
return sec
def __eq__(self, other):
if self.name == other.name and self.sex == self.sex:
return True
return False
a = A('egg','男',38)
b = A('egg','男',37)
print(a,b)
print(set((a,b))) # set 方法去重物件時,依賴物件的__hash__ 和 __eq__ 方法
__eq__
class C:
def __init__(self,name):
self.name = name
def __eq__(self, other):
if self.name == other.name:
return True
else:
return False
# print(self,other)
ob1 = C('egg')
ob2 = C('egg')
print(ob1 == ob2) # False
# 紙牌遊戲 import _json from collections import namedtuple Card = namedtuple('Card',['rank','suit']) # rank牌面的大小 suit 牌面的花色 ranks = [str(n) for n in range(2,11)] + list('JQKA') suits = ['紅心','方板','梅花','黑桃'] print(ranks) lei = [Card(rank,suit) for rank in ranks for suit in suits] print(lei) class FranchDeck: ranks = [str(n) for n in range(2,11)] + list('JQKA') # 生成2到10 和J到A 字串型別的類表 suits = ['紅心','方板','梅花','黑桃' ] # 定義一個類表 def __init__(self): self._cards = [Card(rank,suit) for rank in FranchDeck.ranks for suit in FranchDeck.suits] # 函式巢狀,生成一副撲克牌 def __len__(self): return len(self._cards) def __getitem__(self, item): return self._cards[item] def __setitem__(self, key, value): self._cards[key] = value deck = FranchDeck() # 例項化一個物件 print(deck[0]) # 物件中有__getitem__方法可以使用索引方式檢視屬性 # Card(rank='2', suit='紅心') from random import choice print(choice(deck)) # choice取隨機數牌、 # Card(rank='9', suit='方板') print(choice(deck)) # Card(rank='2', suit='方板') from random import shuffle shuffle(deck) shuffle(deck) print(deck[:5]) # 洗牌用到的,依賴物件的__len__方法紙牌遊戲
class FranchDeck: ranks = [str(n) for n in range(2,11)] + list('JQKA') suits = ['紅心','方板','梅花','黑桃'] def __init__(self): self._cards = [Card(rank,suit) for rank in FranchDeck.ranks for suit in FranchDeck.suits] def __len__(self): return len(self._cards) def __getitem__(self, item): return self._cards[item] def __setitem__(self, key, value): self._cards[key] = value deck = FranchDeck() print(deck[0]) from random import choice print(choice(deck)) print(choice(deck)) from random import shuffle shuffle(deck) print(deck[:5])紙牌遊戲2
class Person: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def __hash__(self): return hash(self.name+self.sex) def __eq__(self, other): if self.name == other.name and self.sex == other.sex:return True p_lst = [] for i in range(84): p_lst.append(Person('egon',i,'male')) print(p_lst) print(set(p_lst))一道面試題