1. 程式人生 > 實用技巧 >我的python學習之路-oop面向物件

我的python學習之路-oop面向物件

本節內容:

  一、類的基礎

    1.1 類的定義

    1.2 .類的例項化

    1.3 類的結構

    1.4 類的命名

二、封裝

    2.1 封裝-物件的操作

    2.2 封裝-類的相關

    2.3 注意點-物件和類之間的不同

    2.4 訪問類中的私有成員

    2.5刪除類物件中公有成員屬性方法

  三、繼承

    3.1 單繼承

    3.2 多繼承

  四、多型

    4.1基本概念及使用例子

  五、魔術方法

    5.1 __init__構造方法

    5.2__new__ 魔術方法

    5.3單態(例)模式

    5.4 __del__ 析構方法

    5.5__call__魔術方法

    5.6__str__魔術方法

    5.7__repr__魔術方法

    5.8__bool__ 魔術方法

    5.9__add__ 魔術方法 (與之相關的 __radd__ 反向加法)

    5.10__len__ 魔術方法

一、類的基礎

1、類的定義

# 推薦使用
class MyCar():
    pass
    
class MyCar:
    pass
    
class MyCar(object):
    pass

2、類的例項化

class MyCar():
    pass
# 類的例項化 / 例項化物件
obj = MyCar()
print(obj)

3、類的基本結構

  1. 成員屬性
  2. 成員方法
class MyCar():
    # 成員屬性
    color = "粉色系"
    # 成員方法
    def didi():
        print("會滴滴的叫")

4、類的命名

類的命名 => 推薦使用大駝峰命名法;
mycar => MyCar
mycat => MyCat
chengfabiao => ChengFaBiao

二、封裝

封裝等級:

  1. 公有:在類的內部和外部都可以訪問到
  2. 私有:在類的內部可以使用,再類外無法呼叫

成員:

  1. 成員屬性
  2. 成員方法

呼叫:

  1. 物件.成員屬性
  2. 物件.成員方法

繫結方法:

  1. 繫結到物件:物件.類中方法()時,系統會自動把該物件當成引數傳遞到方法中;
  2. 繫結到類 :物件.類中方法()或者類.方法()時,系統會自動把該類當成引數傳遞到方法中

1.封裝-物件的相關操作

定義一個類

class Car():
    # 公有成員屬性
    color = "黃色"
    
    # 私有成員屬性
    __price = "200多萬"
    
    # 公有方法
    def run(self):
        # 類內呼叫公有成員  self <=> obj 
        print(self.color,"內部")
        # 類內呼叫私有成員
        print(self.__price)
        print("小車每秒140米的速度前進")
    
    # 私有方法
    def __drive():
        print("小車可以無人駕駛")

(1)例項化的物件訪問公有成員屬性和方法

# 例項化物件
obj = Car()
#
訪問屬性 print(obj.color,"<外部>") # print(obj.__price) #error # 訪問方法 obj.run() # obj.__drive() #error

(2)例項化的物件動態新增公有成員屬性和方法

obj優先呼叫自己的,在呼叫類的,都沒有報錯

  1) 、 新增成員屬性
obj.engine = "16缸發動機"
obj.color = "綠色" # 優先呼叫物件自己的顏色
print(obj.engine)
print(obj.color)
obj.run()
# __dict__ 檢視物件或者類中的內部成員,返回字典
print(obj.__dict__)
print(Car.__dict__)
  2)、新增成員方法

    注意點: 物件.類外方法()時,系統不會自動把該物件當成引數傳遞到該方法中

    (1)、新增無參方法
def dahuangfeng():
    print("變形~ 我叫大黃蜂")
obj.dahuangfeng = dahuangfeng
obj.dahuangfeng()
print(obj.__dict__)
    (2)、新增有參方法

基本版:

def qingtianzhu(name):
    print("變形~ 我叫{}".format(name))

obj.qingtianzhu = qingtianzhu
obj.qingtianzhu("一柱擎天")

升級版 (手動傳遞obj),由於要用物件中的其他的屬性,所以要傳遞obj

def qingtianzhu(obj,name):
    print( "變形~ 我叫{}".format(name) , "顏色為{}".format(obj.color)  )

obj.qingtianzhu = qingtianzhu
obj.qingtianzhu(obj,"擎天柱")

究極版 (自動傳遞obj)

  MethodType => 建立繫結方法(繫結到物件) 讓系統自動幫助我們傳遞obj物件

import types
"""types.MethodType(函式,物件)"""
func = types.MethodType(qingtianzhu,obj)
print(func)
obj.qingtianzhu = func
obj.qingtianzhu("擎天柱")
    (3) 新增lambda 表示式
obj.hongzhizhu = lambda : print("變形~ 我是反派角色紅蜘蛛")
obj.hongzhizhu()

2、封裝 - 類相關操作

定義一個類

class Taxi():
    # 公有成員屬性
    platenum = "粵B 666888"
    # 私有成員屬性
    __earn = "12000"
    
    # 公有方法
    def lake():
        print("計程車經常拉客人~")
    
    # 私有方法
    def __ranquan():
        print("部分司機繞圈圈~")

(1)定義的類訪問公有成員屬性和方法

obj = Taxi()
"""類中的無參方法只能類來呼叫;"""
# obj.lake()
# 成員屬性
print(Taxi.platenum)
# Taxi.__earn error
# 成員方法
Taxi.lake()

(2)定義的類動態新增公有成員屬性和方法

(1)、動態新增成員屬性
Taxi.luntai = "米其林"
print(Taxi.luntai)
print(obj.luntai) #米其林 對用可以呼叫 
print(Taxi.__dict__)
print(obj.__dict__) #{} 看看出物件和類是兩個記憶體空間

(2)、動態新增成員方法
(1) 無參方法
def fangxiangpan():
    print("我是製造方向盤的方法")

Taxi.fangxiangpan = fangxiangpan
Taxi.fangxiangpan()
(2) 有參方法
def engin(name):
    print("我是製造{}的方法".format(name))
Taxi.engin = engin
Taxi.engin("EA888")
(3) lambda表示式
Taxi.zuoyi = lambda : print("我是製造加熱座椅的方法")
Taxi.zuoyi()

3、注意點: 物件和類之間的不同

(1)物件去呼叫類中方法時,系統都會預設傳遞該物件引數;

(2)物件可以預設呼叫類中的公有成員,反過來,類不能呼叫物件中的相關成員.

(3)一個類可以建立多個物件,而物件和物件之間是彼此獨立的;

4、訪問類中私有成員

定義一個類

 1 class Plane():
 2 
 3     # 公有成員屬性
 4     captain = "李雅琪"
 5     
 6     # 私有成員屬性
 7     __airsister = "10個空姐"
 8     
 9     # 公有成員方法
10     def fly(self):
11         print("飛機飛到平流層,可以飛機的機身的抖動")
12     
13     # 私有成員方法
14     def __price(self):
15         print("飛機的價格保密")
16         
17     # 公有無參成員方法
18     def fly2():
19         print("飛機在降落時,落地的一瞬間會向上彈起,請記好安全帶")
20     
21     # 私有無參成員方法
22     def __info():
23         print("關於飛機中的機長和空姐的資訊保密")
24         
25     # 利用公有方法調取私有成員[物件操作]
26     def pub_info1(self):
27         print(self.__airsister)
28         self.__price()
29         
30     # 利用公有方法調取私有成員[類操作]
31     def pub_info2():
32         print(Plane.__airsister)
33         Plane.__info()
View Code

(1 ).方法一 私有化的實現方式:改名策略 (不推薦,破壞了封裝性)

# 例項化物件
obj = Plane()
print(Plane.__dict__)
# 類去訪問私有成員屬性
print(Plane._Plane__airsister)
# 類去訪問私有成員方法
Plane._Plane__info()

# 物件去訪問私有成員屬性
obj._Plane__airsister
# 物件去訪問私有成員方法
obj._Plane__price()

2.方法二 利用一個公有方法,間接呼叫私有成員 (推薦)

obj.pub_info1()
Plane.pub_info2()

注意點:如果無參只能類來調取,如果有參,物件和類都能調取

# obj.pub_info2() #error
Plane.pub_info1(obj)

5、刪除類物件中公有成員屬性方法

1.刪除成員時,一定要注意,該成員歸屬於誰,如果物件中沒有該成員,只有使用的權利,沒有刪除和修改的權利

2.物件獲取成員時,先看自己空間有沒有,如果有就調取,否則上類中成員尋找,如果類中也沒有,直接報錯

定義一個類:

 1 class Plane():
 2 
 3     # 公有成員屬性
 4     captain = "李雅琪"
 5     
 6     # 私有成員屬性
 7     __airsister = "10個空姐"
 8     
 9     # 公有成員方法
10     def fly(self):
11         print("飛機飛到平流層,可以飛機的機身的抖動")
12     
13     # 私有成員方法
14     def __price(self):
15         print("飛機的價格保密")
16         
17     # 公有無參成員方法
18     def fly2():
19         print("飛機在降落時,落地的一瞬間會向上彈起,請記好安全帶")
20     
21     # 私有無參成員方法
22     def __info():
23         print("關於飛機中的機長和空姐的資訊保密")
24         
25     # 利用公有方法調取私有成員[物件操作]
26     def pub_info1(self):
27         print(self.__airsister)
28         self.__price()
29         
30     # 利用公有方法調取私有成員[類操作]
31     def pub_info2():
32         print(Plane.__airsister)
33         Plane.__info()
View Code

1、刪除物件中的屬性

obj.captain = "家營和" # 不能刪除類中的,只能自己新增
print(obj.__dict__)
del obj.captain
print(obj.captain,"<111>") 

2、刪除物件中的方法

obj.pub_info1 = lambda : print("我是pub_info方法")
del obj.pub_info1

3、刪除類中的屬性

del Plane.captain
#print(Plane.captain) error
# print(obj.captain,"<2222>") error

4、刪除類中的方法

del Plane.pub_info1
# Plane.pub_info1(obj) error
# obj.pub_info1() error

三 、繼承

繼承:一個類除了自身所擁有的屬性方法之外,還獲取了另外一個類的成員屬性和方法

被繼承的就是父類(基類,超類)
繼承的就是子類(衍生類)

python中所有類的父類是object

1、單繼承

class Human():
    
    property1 = "遠古人類不穿衣服"
    
    def fire(self):
        print("遠古人類鑽木去火")
    
    def drinkblood(self):
        print("遠古人類茹毛飲血")
    
    def __mao(self):
        print("遠古人類一身毛,不能碰")
        
        
class Man(Human):
    pass

1、子類繼承了父類之後,子類可以使用父類的公有成員

obj = Man()
print(obj.property1)

2、子類繼承了父類之後,子類不能使用父類的私有成員

class Woman(Human):
    def pub_func(self):
        self.__mao()
obj = Woman()
# obj.pub_func() error

3、子類繼承了父類之後,子類可以重寫父類的公有成員

class Children(Human):

    def drinkblood(self):
        print("剛出生的小孩只能喝奶奶")

obj = Children()
obj.drinkblood()

4、總結

在繼承的環境當中,物件的調取順序:
先檢視自己物件中是否含有該成員 => 自己的類是否含有 => 該類的父類是否含有 => 報錯

2、多繼承

1.基本用法

class Father():
    f_pty = "風流倜儻,玉樹臨風,一枝梨花壓海棠"
    def f_hobby(self):
        print("打麻將,吃喝嫖賭,開跑車約妹子")
    
class Mother():
    m_pty = "傾國傾城,貌美如花,一直紅杏出牆來"
    def m_hobby(self):
        print("打麻將,蹦野迪,勾引小鮮肉")

class Daughter(Father,Mother):
    pass
    
obj = Daughter()
print(obj.f_pty)
obj.m_hobby()

2.深度使用

(1)super本身是一個類 super()是一個物件 用於呼叫父類的繫結方法
(2)super() 只應用在繫結方法中,預設自動傳遞self物件 (前提:super所在作用域存在self)
(3)super用途: 解決複雜的多繼承呼叫順序

 1 class Father():
 2     pty = "風流倜儻,玉樹臨風,一枝梨花壓海棠"
 3     def hobby(self):
 4         print(self)
 5         print("打麻將,吃喝嫖賭,開跑車約妹子")
 6     
 7 class Mother():
 8     pty = "傾國傾城,貌美如花,一直紅杏出牆來"
 9     def hobby(self):
10         print("打麻將,蹦野迪,勾引小鮮肉")
11 
12 class Son(Father,Mother):
13     pty = "可愛,有趣,愛學習,愛勞動,三道槓"
14     
15     def hobby(self):
16         print("喜歡打遊戲,lol,wow.dnf.ddo,cs,cf")
17     
18     # 1.使用類呼叫類中成員
19     def skill1(self):
20         # 呼叫mother中的成員
21         print(Mother.pty)
22         Mother.hobby(self)
23         
24         # 呼叫father中的成員
25         print(Father.pty)
26         # Father.hobby()
27     
28     # 2.使用物件呼叫類中成員
29     """obj呼叫成員時,會按照 obj成員 -> 子類成員 -> 父類成員"""
30     def skill2(self):
31         print(self.pty)
32         # obj.hobby() error
33         self.hobby()
34         
35     # 3.使用super呼叫類中成員
36     """1.super只調用父類的繫結方法 2.會自動把該物件當成引數進行傳遞"""
37     def skill3(self):
38         print(super)
39         print(super()) 
40         print(super().pty)
41         super().hobby()
42 
43 obj = Son()
44 print("<=======1========>")
45 obj.skill1()
46 print("<=======2========>")
47 obj.skill2()
48 print("<=======3========>")
49 obj.skill3()
View Code

3、菱形繼承

class Human():
    pty = 4
    def feelT(self):
        print("天熱了,脫毛1")
        print(self.pty)
        print("天冷了,穿貂2")
        
class Man(Human):
    pty = 3
    def feelT(self):
        print("天熱了,光膀子3")
        super().feelT()
        print("天冷了,穿貂4")

class Woman(Human):
    pty = 2
    def feelT(self):
        print("天熱了,脫衣服5")
        super().feelT()
        print("天冷了,多喝熱水6")

class Children(Man,Woman):
    pty = 1
    def feelT(self):
        print("天熱了,光屁股7")
        super().feelT()
        print("天冷了,喝奶8")

obj = Children()
obj.feelT()
# 7 3 5 1 2 6 4 8
print(obj.pty)#1

mro列表:方法解析順序列表

類.mro() => 方法解析順序列表
super呼叫的順序要依賴mro列表所呈現的順序,依次呼叫;
作用: super用途: 解決複雜的多繼承呼叫順序(菱形繼承)

super要點:
1.super只調用父類成員
2.super呼叫父類成員採用廣度優先原則(依照類.mro列表順序呼叫)
3.super呼叫父類方法時,會自動傳遞該物件引數

4、相關函式

(1)、.issubclass 判斷子類與父類 (類與類之間的關係)

  issubclass在判斷子父關係時候,只要在一條繼承鏈上,有繼承關係即可
  1).issubclass(子類,父類)
  2).issubclass(子類,(父類1,父類2,父類3 ... ))

(2)、isinstance 判斷物件的型別 (物件與類之間關係)

  1).isinstance(物件,類)

  2)isinstance(物件,(類1,類2,類3)

四 、多型

1、基本概念及使用例子

多型 : 不同的子類物件,呼叫相同的父類方法,產生不同的執行結果

特徵 : 繼承 重寫 針對於物件

 1 class Soldier():
 2     # 攻擊方法
 3     def attack(self):
 4         pass
 5     
 6     # 撤退方法
 7     def back(self):
 8         pass
 9     
10     
11 class Army(Soldier):
12     def attack(self):
13         print("手撕鬼子,包子手雷")
14     
15     def back(self):
16         print("飛簷走壁,日行八百,夜行一千")
17         
18 class Navy(Soldier):
19     def attack(self):
20         print("扔魚叉,勤撒網,往回拉鬼子")
21         
22     def back(self):
23         print("潛水,划水,水遁,下水憋氣30個小時")
24     
25 class AirForce(Soldier):
26     def attack(self):
27         print("射導彈,扔手雷")
28         
29     def back(self):
30         print("契機跳傘,落地成盒")
31     
32 # 建立陸軍士兵
33 objArmy = Army()
34 # 建立海軍士兵
35 objNavy = Navy()
36 # 建立空軍士兵
37 objAirForce = AirForce()
38 
39 # 各就位準備
40 lst = [objArmy,objNavy,objAirForce]
41 
42 strvar = """
43 各就位準備,將軍請下令:
44 1.全體出擊
45 2.全體撤退
46 3.陸軍上,其他兵種撤退
47 """
48 
49 num = input(strvar)
50 for i in lst:
51     # print(i)
52     if num == "1":
53         i.attack()
54     elif num == "2":
55         i.back()
56     elif num == "3":
57         # 判斷物件型別是陸軍
58         if isinstance(i,Army):
59             i.attack()
60         else:
61             i.back()
62     else:
63         print("風大太,我聽不見~")
64         break
65         
View Code

五、魔術方法

定義:系統自動呼叫的方法,按照觸發機制呼叫

1、__init__構造方法

觸發時機:例項化物件,初始化的時候觸發
功能:為物件新增成員
引數:引數不固定,至少一個self引數
返回值:無

(1) 基本使用-無引數的

class MyClass():
    def __init__(self):
        self.name = "~李琦~"
        print("構造方法被觸發了... ")

# 例項化物件
obj = MyClass()
print(obj.name)

(2)帶有引數的構造方法

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

# 在例項化物件時,給與構造方法實參
obj1 = MyClass("朱培峰")
obj2 = MyClass("黃常見")
print(obj1.name)
print(obj2.name)

(3)類可以是一個,物件可以是多個,不同的物件之間資料彼此隔離

 1 class Children():
 2 
 3     # 構造方法
 4     def __init__(self,name,skin):
 5         # 為物件新增成員
 6         self.name = name
 7         self.skin = skin
 8     # 公有成員方法(繫結到物件)
 9     def cry(self):
10         print("小孩一生產出來,就會哇哇哇的哭")
11 
12     # 公有成員方法(繫結到物件)
13     def eat(self):
14         print("小孩一生產出來,就會吃奶奶")
15 
16     # 私有成員方法(繫結到物件)
17     def __laugh(self):
18         print("小孩一生產出來,就仰天長笑,老子終於出來了.")
19         
20     # 面向物件的寫法(讓物件操作一切) 推薦
21     def info1(self):
22         print("小孩的姓名是{},小孩的膚色是{}".format(self.name , self.skin)  )
23 
24     # 面向過程寫法(普通的函式傳參)
25     def info2(self,name,skin):
26         print("小孩的姓名是{},小孩的膚色是{}".format(name ,skin)  )
27 
28 
29 wanggangdan = Children("王剛單","綜色")
30 wanggangdan.info1()
31 wanggangdan.info2("王鋼單","白色")
32 wanggangdan.cry()
33 
34 wangtiechui = Children("王鐵錘","黑色")
35 wangtiechui.info1()
36 wangtiechui.eat()
37 
38 wangbaoqiang = Children("王寶強","綠色")
39 wangbaoqiang.info1()
40 # wangbaoqiang.__laugh() error
View Code

2、__new__ 魔術方法

觸發時機:例項化類生成物件的時候觸發(觸發時機在__init__之前)
功能:控制物件的建立過程
引數:至少一個cls接受當前的類,其他根據情況決定
返回值:通常返回物件或None

1.基本使用

 1 class OtherClass():
 2     pty = 200
 3 obj2 = OtherClass()
 4 
 5 class MyClass():
 6     pty = 1
 7     def __new__(cls):
 8         print("__new__方法被觸發 ... ")
 9         print(cls)
10         print("<===========>")
11         
12         # 返回本類物件 (借父生子)
13         # 類.方法(cls)
14         # return object.__new__(cls)
15         # 不返回物件
16         # return None
17         # 返回其他類物件
18         return obj2
19 
20 obj = MyClass()
21 print(obj)
22 print(obj.pty)
View Code

2.__new__ 和 __init__ 的觸發時機

__new__ 是在造物件時觸發
__init__ 有物件之後,初始化物件的時候自動觸發
先有物件,在初始化;

3.__new__ 和 __init__ 引數需要一一對應

 1 class MyClass():
 2 
 3     def __new__(cls,name):
 4         print(333)
 5         return object.__new__(cls)
 6     def __init__(self,name):
 7         print(444)
 8         self.name = name
 9         
10 obj = MyClass("李琦")
11 print(obj.name)
12 
13 # 在__new__中加上收集引數,以不變應萬變
14 class MyClass():
15     
16     def __new__(cls,*args,**kwargs):
17         print(333)
18         return object.__new__(cls)
19     def __init__(self,name,sex,age):
20         print(444)
21         self.name = name
22         self.sex = sex
23         self.age = age
24 obj = MyClass("朱培峰","女性","100")
25 print(obj.name)
26 print(obj.sex)
27 print(obj.age)
View Code

4.注意點

如果沒有創建出物件,不會觸發構造方法 ...
如果返回的不是本類物件,不會觸發構造方法 ...

3、單態(例)模式

同一個類,無論例項化多少次,都有且只有一個物件

作用: 可以減少記憶體空間的浪費,提升程式碼執行效率
場景: 如果不需要在建立物件時,在類外額外為當前物件新增成員,就可以使用單態模式;

(1) 基本使用

 1 class SingleTon():
 2     # 類中私有成員屬性
 3     __obj = None
 4     
 5     def __new__(cls):
 6         print(cls) # <class '__main__.SingleTon'>
 7         # 類.私有成員屬性
 8         if cls.__obj is None:
 9             # 儲存建立的物件在私有成員__obj當中
10             # 類.私有成員屬性 = 值(物件)            
11             cls.__obj = object.__new__(cls)
12         # 返回該物件
13         return cls.__obj
14         
15 obj1 = SingleTon()
16 obj2 = SingleTon()
17 obj3 = SingleTon()
18 print(obj1)
19 print(obj2)
20 print(obj3)
View Code

程式碼解析:
obj1 = SingleTon() 觸發__new__魔術方法 if cls.__obj is None: 條件滿足,建立物件賦值給私有成員__obj return 當前建立的物件
obj2 = SingleTon() 觸發__new__魔術方法 return cls.__obj
obj3 = SingleTon() 觸發__new__魔術方法 return cls.__obj

(2) 注意點

 1 class SingleTon():
 2     __obj = None
 3     def __new__(cls,*args,**kwargs):
 4         if cls.__obj is None:
 5             cls.__obj = object.__new__(cls)
 6         return cls.__obj
 7     
 8     def __init__(self,name):
 9         self.name = name
10     
11 obj1 = SingleTon("王永娟")
12 obj2 = SingleTon("荷葉")
13 print(obj1.name) 
14 print(obj2.name)
15 
16 print(obj1,obj2)
17 print(obj1 is obj2) ##相等 同一地址
View Code

4、__del__ 魔術方法(析構方法)

觸發時機:當物件被記憶體回收的時候自動觸發[1.頁面執行完畢回收所有變數 2.所有物件被del的時候]
功能:物件使用完畢後資源回收
引數:一個self接受物件
返回值:無

1.基本使用

 1 # 1.基本使用
 2 class LangDog():
 3     # 構造方法
 4     def __init__(self,name):
 5         self.name = name
 6         
 7     # 析構方法
 8     def __del__(self):
 9         print("析構方法被觸發 ... ")
10 
11 # 1.頁面執行完畢回收所有變數,自動觸發
12 obj1 = LangDog("小白土狗")
13 print(obj1.name)
14 # 2.所有物件被del的時候,自動觸發
15 # print("<==========start==========>")
16 # del obj1
17 # print("<==========end==========>")
18 # 3.注意點
19 """當一個數據沒有任何變數引用的時候,才會真正的被記憶體釋放掉;"""
20 obj2 = obj1
21 obj3 = obj1
22 print(obj2 is obj3)
23 print(obj1,obj2,obj3)
24 print("<==========start==========>")
25 del obj1
26 del obj2
27 del obj3
28 print("<==========end==========>")
View Code

2.模擬檔案操作

 1 import os
 2 class ReadFile():
 3         
 4     def __new__(cls,filename):
 5         # 判斷檔案是否存在,在建立物件
 6         if os.path.exists(filename):
 7             return object.__new__(cls)
 8         else:
 9             print("抱歉,該檔案不存在")
10 
11     def __init__(self,filename):
12         # 開啟檔案
13         self.fp = open(filename,mode="r",encoding="utf-8")
14         
15     def readfile(self):
16         # 讀取檔案
17         data = self.fp.read()
18         return data
19         
20     def __del__(self):
21         # 關閉檔案
22         self.fp.close()
23 
24 obj = ReadFile("ceshi1.txt")
25 # obj = ReadFile("ceshi1.txt234242234423") 檔案不存在,不會建立物件
26 res = obj.readfile()
27 print(res)
View Code

5、__call__ 魔術方法

觸發時機:把物件當作函式呼叫的時候自動觸發

功能: 模擬函式化操作

引數: 引數不固定,至少一個self引數

返回值: 看需求

(1) 基本用法

class MyClass():
    def __call__(self):
        print("__call__ 方法被觸發 ... ")
        
obj = MyClass()
obj()

(2) 模擬洗衣服的過程

 1 class Wash():
 2     def __call__(self,something):
 3         print("正在{}".format(something))
 4         self.step1()
 5         self.step2()
 6         self.step3()        
 7         return "洗完了"
 8         
 9     def step1(self):
10         print("脫衣服,把衣服扔進洗衣機")
11         
12     def step2(self):
13         print("扔點藍月亮,洗衣粉,洗衣皁,金紡... ")
14         
15     def step3(self):
16         print("穿上去,等於晾乾")
17 
18 obj = Wash()
19 
20 # 方法一
21 # obj.step1()
22 # obj.step2()
23 # obj.step3()
24 
25 # 方法二
26 res = obj("洗衣服")
27 print(res)
View Code

(3) 模擬int操作

 1 import math
 2 class MyInt():
 3     def __call__(self,num):
 4         
 5         # 判斷是否是布林型別,做轉換
 6         if isinstance(num,bool):
 7             if num == True:
 8                 return 1
 9             else:
10                 return 0
11                 
12         # 判斷是否是整型,做轉換
13         elif isinstance(num,int):
14             return num
15             
16         # 判斷是否是浮點型,做轉換
17         elif isinstance(num,float):
18             # 方法一
19             """
20             a,b = str(num).split(".")
21             return eval(a)
22             """
23             
24             # 方法二
25             """ceil  floor"""
26             """
27             if num >= 0:
28                 return math.floor(num)
29             else:
30                 return math.ceil(num)
31             """
32                 
33             # 簡寫
34             return math.floor(num) if num >= 0 else math.ceil(num)
35             
36         # 判斷是否是字串
37         elif isinstance(num,str):
38             # 獲取第一為是+或者-,後面全是純數字,可以轉換
39             if (num[0] == "+" or num[0] == "-") and num[1:].isdecimal():
40                 # 判定符號
41                 if num[0] == "+":
42                     sign = 1
43                 else:
44                     sign = -1
45                 # 計算資料
46                 return self.calc(num[1:],sign)
47                 
48             elif num.isdecimal():
49                 return self.calc(num)
50                 
51             else:
52                 return "抱歉,這個算不了"
53             
54     def calc(self,num,sign=1):
55         # print("<========================>")
56         res = num.lstrip("0")
57         if res == "":
58             return 0
59         return eval(res) * sign
60         
61         
62 # int 整型 浮點型 布林型 純數字字串
63 myint = MyInt()
64 # 布林型
65 res = myint(False)
66 print(res)
67 # 整型
68 res = myint(199)
69 print(res)
70 # 浮點型
71 res = myint(5.77)
72 res = myint(-5.77)
73 print(res , type(res))
74 
75 # 字串
76 # res = myint("-00001111")
77 
78 res = myint("asdfasdf") # -1111 ("-000000000000000000000000")
79 print("<============start============>")
80 print(res)
81 print("<============end============>")
82 
83 """
84 print(math.floor(3.15))
85 print(int(3.15))
86 
87 print(math.ceil(-3.15))
88 print(int(-3.15))
89 
90 
91 print(math.floor(0))
92 # print(int(0.13))
93 
94 """
95 
96 print(int("0000000000000000000012121121"))
97 print(int("+0000000000000000000012121121"))
98 print(int("-0000000000000000000012121121"))
View Code

6、__str__ 魔術方法

觸發時機: 使用print(物件)或者str(物件)的時候觸發

功能: 檢視物件

引數: 一個self接受當前物件

返回值: 必須返回字串型別

 1 class Cat():
 2     gift = "抓老鼠"
 3     def __init__(self,name):
 4         self.name = name
 5         
 6     def cat_info(self):
 7         return "小貓名字叫{},天賦是{}".format(self.name,self.gift)
 8         
 9     def __str__(self):
10         return self.cat_info()
11     
12     # (瞭解) __repr__ = __str__
13     
14 tom = Cat("湯姆")
15 # 第一種觸發方式
16 # print(tom)
17 # 第二種觸發方法
18 res = str(tom)
19 print(res)
20 
21 
22 res = repr(tom)
23 print(res)
View Code

7、__repr__ 魔術方法

觸發時機: 使用repr(物件)的時候觸發

功能: 檢視物件,與魔術方法__str__相似

引數: 一個self接受當前物件

返回值: 必須返回字串型別

 1 class Mouse():
 2     gift = "遛貓"
 3     
 4     def __init__(self,name):
 5         self.name = name
 6         
 7     def mouse_info(self):
 8         return "老鼠的名字{},天賦是{}".format(self.name,self.gift)
 9         
10     def __repr__(self):
11         return self.mouse_info()
12 
13     
14 jerry = Mouse("傑瑞")
15 res = repr(jerry)
16 print(res)
17 
18 # 在列印或者str(物件) 仍然可以觸發__repr__
19 # 原因: 系統在底層加入瞭如下語句: __str__ = __repr__
20 print(jerry)
21 res = str(jerry)
22 print(res)
View Code

8、__bool__ 魔術方法

觸發時機:使用bool(物件)的時候自動觸發

功能:強轉物件

引數:一個self接受當前物件

返回值:必須是布林型別

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

__complex__(self) 被complex強轉物件時呼叫

__int__(self) 被int強轉物件時呼叫

__float__(self) 被float強轉物件時呼叫

1 class MyClass():
2     def __bool__(self):
3         return False
4     
5 obj = MyClass()
6 # 強轉物件時自動觸發
7 print(bool(obj))
View Code

9、_add__ 魔術方法 (與之相關的 __radd__ 反向加法)

觸發時機:使用物件進行運算相加的時候自動觸發

功能:物件運算

引數:二個物件引數

返回值:運算後的值

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

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

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

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

 1 class MyClass():
 2     def __init__(self,num):
 3         self.num = num
 4         
 5     # 物件 在加號的左邊,自動觸發__add__魔術方法
 6     def __add__(self,other):
 7         print(self) # a
 8         print(other)# 5
 9         return self.num + other # 15
10         
11     # 物件 在加號的右邊,自動觸發__radd__魔術方法
12     def __radd__(self,other):
13         print(self) # b
14         print(other)# 3
15         return self.num + 2 * other
16         
17 # 寫法一
18 a = MyClass(10)
19 res = a + 5
20 print(res)
21 
22 # 寫法二
23 b = MyClass(5)
24 res = 3 + b
25 print(res)
26 
27 # 寫法三
28 """
29 先觸發add方法:self => a , other => b return self.num + other => return 10 + b =>   res = 10 + b
30 再觸發radd方法:self => b , other => 10 return 5 + 2 * 10 = 5 + 20 = 25
31 """
32 res = a + b
33 print(res)
34 
35 #  25 25 25
View Code

10、__len__ 魔術方法

觸發時機:使用len(物件)的時候自動觸發

功能:用於檢測物件中或者類中某個內容的個數

引數:一個self接受當前物件

返回值:必須返回整型

 1 class MyClass():
 2     pty1 = 1
 3     pty2 = 2
 4     __pty3 = 3
 5     __pty4 = 3
 6     
 7     def func1():
 8         pass
 9     def func2():
10         pass
11     def __func3():
12         pass
13     
14     def __len__(self):
15         # 基本寫法
16         """
17         lst = []
18         print(MyClass.__dict__)
19         dic = MyClass.__dict__
20         for i in dic:
21             print(i,type(i))
22             if not (i.startswith("__") and i.endswith("__")):
23                 lst.append(i)
24         return len(lst)
25         """
26                 
27         # 優化程式碼
28         return len([i for i in MyClass.__dict__ if not (i.startswith("__") and i.endswith("__"))])
29         
30         
31 
32 obj = MyClass()
33 res = len(obj)
34 print(res)
View Code

觸發時機:把物件當作函式呼叫的時候自動觸發功能: 模擬函式化操作引數: 引數不固定,至少一個self引數返回值: 看需求