python面向對象基礎(三)內置方法 __xx__

__str__和__repr__,__format__

改變對象的字符串顯示__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)

__del__

析構方:當對象在內存中被釋放的同時自動觸發執行該方法。app

注:此方法通常無須定義,由於Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,由於此工做都是交給Python解釋器來執行,因此,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的。ide

class Foo:

    def __del__(self):
        print('執行我啦')

f1=Foo()
del f1
# 執行我啦
print('------->')
f1
# NameError: name 'f1' is not defined
  item系列

__getitem__\__setitem__\__delitem__

  ==》__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__

發現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__(),該方法將最大限度地收集參數信息。

dir([object])

參數說明:

  • object -- 對象、變量、類型。
class A(object): pass
a=A()
a.name="wqbin"

print(A.__dict__)
print(a.__dict__)
print(a.__dir__())

 

 

 Note:dir是最大範圍的收集一個類或者一個對象的屬性,因此是包含__dict__.keys

 

 

__call__

對象後面加括號,觸發執行。

對於 __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))

 

__len__

果一個類表現得像一個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

 

__hash__

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__

__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__()方法。

 

大多數人都覺得是才智成就了科學家,他們錯了,是品格。---愛因斯坦
相關文章
相關標籤/搜索