改變對象的字符串顯示__str__,__repr__python
自定製格式化字符串__format__程序員
#_*_coding:utf-8_*_ format_dict={ '格式1':'{obj.name}-{obj.addr}-{obj.type}',#學校名-學校地址-學校類型 '格式2':'{obj.type}:{obj.name}:{obj.addr}',#學校類型:學校名:學校地址 '格式3':'{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='格式1' fmt=format_dict[format_spec] return fmt.format(obj=self) s1=School('清華','北京','公立') print('from repr: ',repr(s1)) print('from str: ',str(s1)) print(s1) ''' str函數或者print函數--->obj.__str__() repr或者交互式解釋器--->obj.__repr__() 若是__str__沒有被定義,那麼就會使用__repr__來代替輸出 ''' ''' 注意:這三個方法的返回值必須是字符串,不然拋出異常 ''' print(format(s1,'格式1')) print(format(s1,'格式2')) print(format(s1,'格式3')) print(format(s1,'xxx'))
class B: def __str__(self): return 'str : class B' def __repr__(self): return 'repr : class B' b=B() print('%s'%b) print('%r'%b)
析構方:當對象在內存中被釋放的同時自動觸發執行該方法。app
注:此方法通常無須定義,由於Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,由於此工做都是交給Python解釋器來執行,因此,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的。ide
class Foo: def __del__(self): print('執行我啦') f1=Foo() del f1 # 執行我啦 print('------->') f1 # NameError: name 'f1' is not defined
==》__dict__函數
在Python中,若是咱們想實現建立相似於序列和映射的類,能夠經過重寫魔法方法__getitem__、__setitem__、__delitem__方法去模擬。orm
這些魔術方法的原理就是:當咱們對類的屬性item進行下標的操做時,首先會被__getitem__()、__setitem__()、__delitem__()攔截,從而進行咱們在方法中設定的操做,如賦值,修改內容,刪除內容等等。對象
對類的屬性item進行下標的操做==>obj["屬性"]blog
class A: def __init__(self,name): self.name=name def __getitem__(self, item): print("呵呵你看不到") def __setitem__(self, key, value): self.__dict__[key]=value print('設置了 obj 屬性 [%s] 爲 %s'%(key,value)) def __delitem__(self, key): print('del obj[%s]時,我執行'%key) self.__dict__.pop(key) def __delattr__(self, item): print('del obj.%s時,我執行'%item) self.__dict__.pop(item) def __setattr__(self, item,value): print("調用了__setattr__方法") self.__dict__[item]=value def daren(self): pass a=A('斌哥') #這個過程也調用了__setattr__方法 print(a.__dict__) # {'name': '斌哥'} a.name #==>'斌哥' print(a['name']) #調用了__getitem__方法 # 呵呵你看不到 # None a['age']=18 #=觸發=__setitem__>設置了 obj 屬性 [age] 爲 18 a.age=19 #=觸發=__setitem__>調用了__setattr__方法 a['appear']='很帥' # #=觸發=>設置了 obj 屬性 [appear] 爲 很帥 del a.appear #觸發__delattr__==>del obj.appear時,我執行 del a['age'] #觸發__delitem__==>del obj[age]時,我執行 a.school='nc' print(a.__dict__) # {'school': 'nc', 'name': '斌哥'} # 結論:感受屬性維護了一個doc字典 # 結論 : obj.屬性 調用 使用的是xxattr()方法 #xxitem()方法提供了 訪問屬性一個【】接口
發現dict是一個mappingproxy類型,爲什麼不是一個簡單的python dict呢?接口
>>> class A(object): pass ... >>> A.__dict__ mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None})
不清楚,回頭研究下。內存
Python的實例有本身的__dict__,它對應的類也有本身的__dict__ (可是有些特殊的對象是沒有__dict__屬性的)
class A: def __init__(self,name): self.name=name def __len__(self): return len(self) a=A('斌哥') print(A.__dict__) # {'__doc__': None, '__module__': '__main__', '__len__': <function A.__len__ at 0x0000014FF1C71EA0>, # '__init__': <function A.__init__ at 0x0000014FF1BE1730>, '__weakref__': <attribute '__weakref__' of 'A' objects>, # '__dict__': <attribute '__dict__' of 'A' objects>} print(a.__dict__) # {'name': '斌哥'} class B(A): def __init__(self,age,name): super().__init__(name) self.age=age def __len__(self): return len(self) b=B(18,"bb") print(B.__dict__) print(b.__dict__) # {'__doc__': None, '__module__': '__main__', # '__init__': <function B.__init__ at 0x0000014FF1CB1A60>, # '__len__': <function B.__len__ at 0x0000014FF1CB1730>} # # {'name': 'bb', 'age': 18}
class A: a = 0 b = 1 def __init__(self): self.a = 2 self.b = 3 def test(self): print('a normal func.') @staticmethod def static_test(a): print('a static func.'+a) @classmethod def class_test(cls): print('a calss func.') obj = A() print(A.__dict__) print(obj.__dict__) A.static_test("1") A.class_test()
1.類的靜態函數、類函數、普通函數、全局變量以及一些內置的屬性都是放在類__dict__裏的
2.對象的屬性(不含類的)保存在實例__dict___裏
3.子類有本身的__dict__, 父類也有本身的__dict__,子類的全局變量和函數放在子類的dict中,父類的放在父類dict中。對象也這樣。
4.內置的數據類型沒有__dict__屬性
dir() 函數不帶參數時,返回當前範圍內的變量、方法和定義的類型列表;帶參數時,返回參數的屬性、方法列表。若是參數包含方法__dir__(),該方法將被調用。若是參數不包含__dir__(),該方法將最大限度地收集參數信息。
dir([object])
參數說明:
class A(object): pass a=A() a.name="wqbin" print(A.__dict__) print(a.__dict__) print(a.__dir__())
Note:dir是最大範圍的收集一個類或者一個對象的屬性,因此是包含__dict__.keys
對象後面加括號,觸發執行。
對於 __call__ 方法的執行是由對象後加括號觸發的,即:對象() 或者 類()()
class C: def __init__(self): print("__init__") def __call__(self, *args, **kwargs): print('__call__') obj = C() # 執行 __init__ obj() # 執行 __call__
爲何函數對象能夠觸發?
f = abs print(dir(f))
果一個類表現得像一個list,要獲取有多少個元素,就得用 len() 函數。
要讓 len() 函數工做正常,類必須提供一個特殊方法__len__(),它返回元素的個數。
class A: def __init__(self): self.a = 1 self.b = 2 def __len__(self): return len(self.__dict__) a = A() print(len(a))
#2
class A: def __init__(self): self.a = 1 self.b = 2 def __hash__(self): return hash(str(self.a)+str(self.b)) a = A() print(hash(a))
class A: def __init__(self): self.a = 1 self.b = 2 def __hash__(self): # return str(self.a)+'哈哈'+str(self.b) return int(str(1024)+str(self.a)+str(self.b)) a = A() print(hash(a)) # TypeError: __hash__ method should return an integer
__eq__ 當判斷兩個對象的是否相等時,==觸發此方法
class A: def __init__(self): self.a = 1 self.b = 2 def __eq__(self,obj): if self.a == obj.a and self.b == obj.b: return True a = A() b = A() print(a == b) #true
== 比較的是兩個對象的內容是否相等,即內存地址能夠不同,內容同樣就能夠了。這裏比較的並不是是同一片葉子,可能葉子的種類或者脈絡相同就能夠了。默認會調用對象的 __eq__()方法。