day25:7個魔術方法&5個關於類的魔術屬性

目錄

1.__del__(析構方法)

2.魔術方法:__str__

3.魔術方法:__repr__

4.魔術方法:__call__

5.魔術方法:__bool__

6.魔術方法:__add__&__radd__

7.魔術方法:__len__

8.與類相關的魔術屬性

一個小表格方便記憶哈

__del__ (析構方法)

__del__簡要介紹

1.觸發時機:當對象被內存回收的時候自動觸發

  (1)頁面執行完畢回收所有變量

  (2)所有對象被del的時候

2.功能:對象使用完畢後資源回收

3.參數:一個self接受對象

4.返回值:

第一種情況:頁面執行完畢回收所有變量

class LangDog():
    food = "改吃蔬菜"

    def __init__(self, name):
        self.name = name

    def __del__(self):
        print("析構方法被觸發")
print("0001=====")
obj = LangDog("肉絲")
print("0002=====")
# 1.頁面執行完畢回收所有變量
print(obj.name) # 當執行完這句話後,才算頁面執行完畢,這個時候觸發__del__析構方法

'''
運行結果:
=====
=====
肉絲
析構方法被觸發
'''

第二種情況:所有對象被del的時候

如何理解第二種情況中所說到的所有對象

代碼如下:

class LangDog():
    food = "改吃蔬菜"

    def __init__(self, name):
        self.name = name

    def __del__(self):
        print("析構方法被觸發")

obj1 = LangDog("肉絲")
obj2 = obj1
print("<=====start=====>")
del obj1
print("<=====end=====>")

打印結果:

雖然obj1對象被刪除了,但是obj2對象並沒有被刪除,所以不會觸發析構方法

打印了「析構方法被觸發」是因為整個頁面執行完畢了,也會觸發析構方法

使用__del__模擬文件操作

# 3.模擬文件操作
import os
class ReadFile():    
    def __new__(cls,filename):
        if os.path.exists(filename): # 判斷文件路徑是否存在
            return object.__new__(cls) # 如果文件存在,創建文件對象
        else:
            return print("該文件是不存在的") # 如果文件不存在,給予錯誤提示

    def __init__(self,filename):
        # 打開文件
        self.fp = open(filename,mode="r+",encoding="utf-8")
        
    def readcontent(self):
        # 讀取文件
        return self.fp.read()
    
    def __del__(self):
        # 關閉文件
        self.fp.close()
    
obj = ReadFile("1.txt")

if obj is not None:
    res = obj.readcontent()
    print(res)
else:
    print("沒有該類文件")


# 當然,也可以用三元運算符來實現
""" 真值 if 條件表達式 else 假值 """
print(obj.readcontent()) if obj is not None else print("沒有該類文件")

魔術方法:__str__

__str__簡要介紹

1.觸發時機: 使用print(對象)或者str(對象)的時候觸發

2.功能: 查看對象

3.參數: 一個self接受當前對象

4.返回值: 必須返回字符串類型

class Cat():
    gift = "小貓咪會賣萌求貓糧,小貓咪抓老鼠"
    def __init__(self,name):
        self.name = name
        
    def __str__(self):
        return self.cat_info()
        
    def cat_info(self):
        return "小貓咪的名字是{},小貓咪{}元".format(self.name,5000)
    
    # __repr__ = __str__
    
tom = Cat("湯姆")
# 方法一. print(對象)
print(tom)
# 方法二. str(對象)
res = str(tom)
print(res)

魔術方法:__repr__

1.觸發時機: 使用repr(對象)的時候觸發

2.功能: 查看對象,與魔術方法__str__相似

3.參數: 一個self接受當前對象

4.返回值: 必須返回字符串類型

class Mouse():
    gift = "偷糧食"
    def __init__(self,name):
        self.name = name
        
    def __repr__(self):
        return self.mouse_info()
        
    def mouse_info(self):
        return "名字是{},龍生龍,鳳生鳳,老鼠的兒子會打洞,還會{}".format(self.name,self.gift)
    
    # 系統在底層,自動加了一句賦值操作
    __str__ = __repr__
        
jerry = Mouse("傑瑞")
res = repr(jerry)
print(res)

# 因為系統底層賦值的原因,在打印對象或者強轉對象為字符串的時候,仍然可以觸發;
print(jerry)
res = str(jerry)
print(res)

魔術方法:__call__

1.觸發時機:把對象當作函數調用的時候自動觸發

2.功能: 模擬函數化操作

3.參數: 參數不固定,至少一個self參數

4.返回值: 看需求

基本用法

# (1) 基本用法
class MyClass():
    a = 1
    def __call__(self):
        print("call魔術方法被觸發了")

obj = MyClass() # 實例化一個對象
obj() # 把對象當做函數調用,此時會觸發__call__方法

模擬洗衣服的過程

# (2) 模擬洗衣服的過程
class Wash():

    def __call__(self,something):
        print("我現在要洗{}".format(something))
        self.step1()
        self.step2()
        self.step3()
        return "洗完了"

    def step1(self):
        print("加熱水,家洗衣粉,加洗衣液,加洗滌劑")

    def step2(self):
        print("衣服泡進去攪亂 打散 搓一搓~ ")

    def step3(self):
        print("脫水,穿上")

obj = Wash()

# 方法一
# obj.step1()
# obj.step2()
# obj.step3()

# 方法二
res = obj("衣服") # 把對象obj當做函數進行調用,此時觸發__call__方法,執行__call__方法所有內容
print(res)

模擬內置的int方法,實現相應的操作(有時間再分析)

# (3) 模擬內置int 實現相應的操作
import math
class MyInt():

    def calc(self,num,sign=1):
        # print(num,sign)
        
        # 去掉左邊多餘的0
        strvar = num.lstrip("0")
        # print(strvar)
        
        # 為了防止都是0 ,如果去掉之後為空,返回0
        if strvar == "":
            return 0
        
        # 正常情況下,執行存數字字符串變成數字 , 在乘上相應的符號,得出最後的結果
        return eval(strvar) * sign

    def __call__(self,num):
        if isinstance(num , bool):
            if num  == True:
                return 1
            elif num == False:                
                return 0
                
        elif isinstance(num,int):
            return num
            
        elif isinstance(num,float):
            # 方法一
            """
            strvar = str(num)
            lst = strvar.split(".")
            return eval(lst[0])
            """
            # 方法二
            """
            if num >= 0:
                return math.floor(num)
            else:
                return math.ceil(num)
            """
            return math.floor(num) if num >= 0 else  math.ceil(num)
        
        elif isinstance(num,str):
            if (num[0] == "+" or num[0]== "-") and num[1:].isdecimal():
                if num[0] == "+":
                    sign = 1
                else:
                    sign = -1                    
        
                return self.calc(num[1:],sign)
                
            elif num.isdecimal():
                return self.calc(num)
            else:
                return "老鐵,這個真轉不了"
        

myint = MyInt()
# myint(5) => 5
# myint(3.14) => 3

res = myint(True)
print(res)
res = myint(100)
print(res)
res = myint(3333.14)
print(res, type(res)) # 3
# bool int float "12312312323"


# int(3.14) => 3
print(int(3.14))  # 3
print(int(-3.14)) # -3
print("<===>")
print(myint(3.14))
print(myint(-0.2))

print("<===>")
print(int("0000000000000000000000000000000000000000001230000000"))
print(int("00000000000000000000000000000000000000000"),"1111222333")
print(int("+000000000000000000000000000000000000000000123"))
print(int("-000000000000000000000000000000000000000000123"))
print(int("000000000000000000000000000000000000000000123"))

print("<==111=>")
print(myint("+000000000234"))
print(myint("000000000000000000000000000000000000000000123"))
print(myint("456899200"))
print(myint("3.143434"))
print(myint(+-++-+-+-+-+-+-+-+-+-+-++++++++-----234234),"<====>")
print(int(+-++-+-+-+-+-+-+-+-+-+-++++++++-----234234),"<====>")

"""
exec("a = 3")
print(a)

eval("4")
"""
# print(math.floor(0.14)) # 0
# print(math.floor(3.14)) # 3
# print(math.ceil(-3.14))  # -3

魔術方法:__bool__

__bool__簡要介紹

1.觸發時機:使用bool(對象)的時候自動觸發

2.功能:強轉對象

3.參數:一個self接受當前對象

4.返回值:必須是布爾類型

class MyClass():
    def __bool__(self):
        return False
    
obj = MyClass()
res = bool(obj)
print(res)

類似的還有如下等等(了解):

__complex__(self) 被complex強轉對象時調用

__int__(self) 被int強轉對象時調用

__float__(self) 被float強轉對象時調用

魔術方法:__add__,__radd__

__add__簡要介紹

1.觸發時機:使用對象進行運算相加的時候自動觸發

2.功能:對象運算

3.參數:二個對象參數

4.返回值:運算後的值

5.注意點:

  對象在加號+的左側時,自動觸發__add__方法

  對象在加號+的右側時,自動觸發__radd__方法

  加號左側和右側都是對象時,先觸發__add__方法,再觸發__radd__方法

class MyClass1():
    def __init__(self,num):
        self.num = num
        
    # 對象在加號+的左側時,自動觸發
    def __add__(self,other):
        # print(self)
        # print(other)
        return self.num + other # return 10 + 7 = 17
        
    # 對象在加號+的右側時,自動觸發
    def __radd__(self,other):
        # print(self)
        # print(other)
        return self.num * 2 + other

# 第一種
a = MyClass1(10)
res = a + 7 
print(res) 

# 第二種
b = MyClass1(5)
res = 20 + b
print(res)

# 第三種
print("<============>")
res = a+b
print(res)
"""
第一次觸發魔術方法, a+ =>觸發__add__方法
self => a other => b
self.num + other => a.num+ b => 10 + b

res = 10 + b
第二次觸發魔術方法 __radd__
self => b other=> 10
self.num * 2 + other => b.num*2 + other => 5 * 2 + 10 => 20
res = 20 
"""

類似的還有如下等等(了解):

__sub__(self, other) 定義減法的行為:-

__mul__(self, other) 定義乘法的行為:*

__truediv__(self, other) 定義真除法的行為:/

魔術方法:__len__

__len__簡要介紹

1.觸發時機:使用len(對象)的時候自動觸發

2.功能:用於檢測對象中或者類中成員的個數

3.參數:一個self接受當前對象

4.返回值:必須返回整型

class MyClass():
    pty1 = 1
    pty2 = 2
    __pty3 = 3
    pyt3  =10
    pty100 = 90
    
    def func1():
        pass
        
    def __func2():
        pass
        
    def __func3():
        pass
    
    def __len__(self):
        lst = []
        dic = MyClass.__dict__
        # 方法一

        # print(MyClass.__dict__) # 獲取類當中的所有成員
        # print(object.__dict__) # 獲取對象中的所有成員
        dic = MyClass.__dict__ # 遍歷類中所有成員
        for i in dic: # 遍歷類中所有成員
            if not(i.startswith("__") and i.endswith("__")): # 如果開頭和結尾都不是以雙下劃線結尾
                lst.append(i) # 將符合條件的成員添加到列表中
                
        return len(lst) 

        # 方法二
        lst = [i for i in dic if  not(i.startswith("__") and i.endswith("__"))]
        return len(lst)

與類相關的魔術屬性

__dict__ 獲取對象或類的內部成員結構

__doc__ 獲取對象或類的內部文檔

__name__ 獲取類名函數名

__class__ 獲取當前對象所屬的類

__bases__ 獲取一個類直接繼承的所有父類,返回元組

class Man():
    pass
    
class Woman():
    pass
    
class Children(Man,Woman):

    """
    功能: 描述小孩天生的屬性
    成員屬性:eye , skin
    成員方法:skylight , moonread , __makebaby    
    """

    eye = "萬花筒血輪眼"
    skin = "白色"
    
    def skylight(self):
        print("宇智波家族的小孩,天生能夠發動天照技能")
        
    def moonread(self,func):
        # func = func111
        print("宇智波家族的小孩,能夠發動月亮的光照消滅你~")
        res = func.__name__
        print(res,type(res))
    
    def __makebaby(self):
        print("這一手招數,只能我自己用")
    
    

# __dict__ 獲取對象或類的內部成員結構
obj = Children()
print(obj.__dict__)
print(Children.__dict__)


# __doc__  獲取對象或類的內部文檔
print(obj.__doc__)
print(Children.__doc__)

# __name__ 獲取類名函數名
def func111():    
    print("我是func111方法")
# 獲取函數名
obj.moonread(func111)
# 獲取類名
obj.moonread(Man)

# __class__ 獲取當前對象所屬的類
print(obj.__class__)

# __bases__ 獲取一個類直接繼承的所有父類,返回元組
print(Children.__bases__)