【python之路面向對象】初級篇

概述

  • 面向過程:根據業務邏輯從上到下寫壘代碼
  • 函數式:將某功能代碼封裝到函數中,往後便無需重複編寫,僅調用函數便可
  • 面向對象:對函數進行分類和封裝,讓開發「更快更好更強...」

面向過程編程最易被初學者接受,其每每用一長段代碼來實現指定功能,開發過程當中最多見的操做就是粘貼複製,即:將以前實現的代碼塊複製到現需功能處。python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
while  True
     if  cpu利用率 >  90 % :
         #發送郵件提醒
         鏈接郵箱服務器
         發送郵件
         關閉鏈接
 
     if  硬盤使用空間 >  90 % :
         #發送郵件提醒
         鏈接郵箱服務器
         發送郵件
         關閉鏈接
 
     if  內存佔用 >  80 % :
         #發送郵件提醒
         鏈接郵箱服務器
         發送郵件
         關閉鏈接

隨着時間的推移,開始使用了函數式編程,加強代碼的重用性和可讀性,就變成了這樣:編程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def  發送郵件(內容)
     #發送郵件提醒
     鏈接郵箱服務器
     發送郵件
     關閉鏈接
 
while  True
 
     if  cpu利用率 >  90 % :
         發送郵件( 'CPU報警' )
 
     if  硬盤使用空間 >  90 % :
         發送郵件( '硬盤報警' )
 
     if  內存佔用 >  80 % :
         發送郵件( '內存報警'

今天咱們來學習一種新的編程方式:面向對象編程(Object Oriented Programming,OOP,面向對象程序設計)
注:Java和C#來講只支持面向對象編程,而python比較靈活即支持面向對象編程也支持函數式編程服務器

建立類和對象

面向對象編程是一種編程方式,此編程方式的落地須要使用 「類」 和 「對象」 來實現,因此,面向對象編程其實就是對 「類」 和 「對象」 的使用。python2.7

  類就是一個模板,模板裏能夠包含多個函數,函數裏實現一些功能ide

  對象則是根據模板建立的實例,經過實例對象能夠執行類中的函數函數式編程

  • class是關鍵字,表示類
  • 建立對象,類名稱後加括號便可

ps:類中的函數第一個參數必須是self(詳細見:類的三大特性之封裝)
   類中定義的函數叫作 「方法」函數

#!usr/bin/env python
# -*- coding:utf-8 -*-
#建立類
class Foo:
    def Bar(self):
        print('Bar')
    def Hello(self,name):
        print('hello %s' %name)
#根據類Foo建立對象
foo = Foo()
foo.Bar()  #執行Bar方法
foo.Hello('SUNXIAO')  #執行Hello方法

內部實際傳參數的邏輯: foo.Hello('SUNXIAO')  --> Hello(self  = foo,name = 'SUNXIAO')學習

誒,你在這裏是否是有疑問了?使用函數式編程和麪向對象編程方式來執行一個「方法」時函數要比面向對象簡便this

  • 面向對象:【建立對象】【經過對象執行方法】
  • 函數編程:【執行函數】

觀察上述對比答案則是確定的,而後並不是絕對,場景的不一樣適合其的編程方式也不一樣。spa

總結:

1)函數式的應用場景 --> 各個函數之間是獨立且無共用的數據

2)面向對象的使用場景:

A、同一類型的方法具備相同的參數時,直接封裝到對象中便可

B、把類當作模板,建立多個對象,對象內封裝的數據能夠不同

self詳解

#!usr/bin/env python
# -*- coding:utf-8 -*-
#建立類
class Foo:
    def Bar(self):
        print('Bar',self)  #self打印:<__main__.Foo object at 0x000001EC4601ADA0>
    def Hello(self,name):
        print('hello %s' %name)
#根據類Foo建立對象
foo1 = Foo()
print(foo1)
foo1.Bar()  #執行Bar方法,打印出:Bar <__main__.Foo object at 0x000001EC4601ADA0>

#由上面的代碼結果能夠看出,在執行Bar方法時,python自動將對象foo1傳遞了Bar方法做爲第一個參數

面向對象三大特性

面向對象的三大特性是指:封裝、繼承和多態。

1、封裝

封裝,顧名思義就是將內容封裝到某個地方,之後再去調用被封裝在某處的內容。

因此,在使用面向對象的封裝特性時,須要:

  • 將內容封裝到某處
  • 從某處調用被封裝的內容

第一步:將內容封裝到某處

__init__(self)爲構造方法,當建立對象時,首先執行的就是構造方法

__del__()  析構方法,當解釋器銷燬對象時自動調用該方法

 self 是一個形式參數,當執行 obj1 = Foo('wupeiqi', 18 ) 時,self 等於 obj1

                              當執行 obj2 = Foo('alex', 78 ) 時,self 等於 obj2

因此,內容其實被封裝到了對象 obj1 和 obj2 中,每一個對象中都有 name 和 age 屬性,在內存裏相似於下圖來保存。

第二步:從某處調用被封裝的內容

調用被封裝的內容時,有兩種狀況:

  • 經過對象直接調用
  • 經過self間接調用

一、經過對象直接調用被封裝的內容

上圖展現了對象 obj1 和 obj2 在內存中保存的方式,根據保存格式能夠如此調用被封裝的內容:對象.屬性名

class Foo:
    def __init__(self,name,age):
        self.name = name
        self.age = age
obj1 = Foo('sunxiao',28)
print(obj1.name) #sunxiao
print(obj1.age) #28

obj2 = Foo('sunyu','23')
print(obj2.name) #sunyu
print(obj2.age) #23
直接調用

二、經過self間接調用被封裝的內容

執行類中的方法時,須要經過self間接調用被封裝的內容

class Foo:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def detail(self):
        print(self.name)
        print(self.age)
obj1 = Foo('sunxiao',28)
obj1.detail()  # Python默認會將obj1傳給self參數,即:obj1.detail(obj1),因此,此時方法內部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18

obj2 = Foo('sunyu','23')
obj2.detail() # Python默認會將obj2傳給self參數,即:obj1.detail(obj2),因此,此時方法內部的 self = obj2,即:self.name 是 alex ; self.age 是 78
簡介調用

綜上所述,對於面向對象的封裝來講,其實就是使用構造方法將內容封裝到 對象 中,而後經過對象直接或者self間接獲取被封裝的內容。

練習一:在終端輸出以下信息

  • 小明,10歲,男,上山去砍柴
  • 小明,10歲,男,開車去東北
  • 小明,10歲,男,最愛大保健
  • 老李,90歲,男,上山去砍柴
  • 老李,90歲,男,開車去東北
  • 老李,90歲,男,最愛大保健
  • 老張...
def kanchai(name,age,gender):
    print('%s,%s歲,%s,上山去砍柴' %(name,age,gender))
def qudongbei(name,age,gender):
    print('%s,%s歲,%s,去東北' %(name,age,gender))
def dabaojian(name,age,gender):
    print('%s,%s歲,%s,大保健' %(name,age,gender))

kanchai('小敏',20,'')
qudongbei('小明',18,'')
dabaojian('老張',65,'')
函數式編程
class Person:
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
    def kanchai(self):
        print('%s,%s歲,%s,上山去砍柴' %(self.name,self.age,self.gender))
    def qudongbei(self):
        print('%s,%s歲,%s,開車去東北' %(self.name,self.age,self.gender))
    def dabaojian(self):
        print('%s,%s歲,%s,最愛大保健' %(self.name,self.age,self.gender))
p1 = Person('xiaoming','18','')
p1.kanchai()
p1.qudongbei()
p2 = Person('老張',65,'')
p2.dabaojian()
面向對象編程
上述對比能夠看出,若是使用函數式編程,須要在每次執行函數時傳入相同的參數,若是參數多的話,又須要粘貼複製了...  ;而對於面向對象只須要在建立對象時,將全部須要的參數封裝到當前對象中,以後再次使用時,經過self間接去當前對象中取值便可。

 

練習二:遊戲人生程序

一、建立三個遊戲人物,分別是:

  • 梅超風,女,18,初始戰鬥力1000
  • 張三丰,男,20,初始戰鬥力1800
  • 黃蓉,女,19,初始戰鬥力2500

二、遊戲場景,分別:

  • 草叢戰鬥,消耗200戰鬥力
  • 自我修煉,增加100戰鬥力
  • 多人遊戲,消耗500戰鬥力
#!usr/bin/env python
#-*- coding:utf-8 -*-
class Person:
    def __init__(self,name,gender,age,fight):
        self.name = name
        self.gender = gender
        self.age = age
        self.fight = fight
    def grassland(self):
        """註釋:草叢戰鬥,消耗200戰鬥力"""
        self.fight -= 200
    def practice(self):
        """註釋:自我修煉,增加100戰鬥力"""
        self.fight += 100
    def commandfight(self):
        """多人遊戲:消耗500戰鬥力"""
        self.fight -= 500
    def detail(self):
        temp = '姓名%s;性別%s;年齡%s;戰鬥力%s' %(self.name,self.gender,self.age,self.fight)
        print(temp)

p1 = Person('sun','',100,10000)
p1.detail()
p1.commandfight()
p1.detail()
遊戲人生

 

 

2、繼承

繼承,面向對象中的繼承和現實生活中的繼承相同,即:子能夠繼承父的內容。

例如:

  貓能夠:喵喵叫、吃、喝、拉、撒

  狗能夠:汪汪叫、吃、喝、拉、撒

若是咱們要分別爲貓和狗建立一個類,那麼就須要爲 貓 和 狗 實現他們全部的功能,以下所示:

上述代碼不難看出,吃、喝、拉、撒是貓和狗都具備的功能,而咱們卻分別的貓和狗的類中編寫了兩次。若是使用 繼承 的思想,以下實現:

  動物:吃、喝、拉、撒

     貓:喵喵叫(貓繼承動物的功能)

     狗:汪汪叫(狗繼承動物的功能)

#!usr/bin/env python
# -*- coding:utf-8 -*-
class Animal:
    def eat(self):
        print('%s吃' %self.name)
    def drink(self):
        print('%s喝' %self.name)
    def shit(self):
        print('%s拉' %self.name)
    def pee(self):
        print('%撒' %self.name)
class Cat(Animal):
    def __init__(self,name):
        self.name = name
    def cry(self):
        print('喵喵叫')
class Dog(Animal):
    def __init__(self,name):
        self.name = name
    def cry(self):
        print('汪汪叫')

dog1 = Dog('老李家的小狗')
dog1.eat()
dog1.cry()
cat1 = Cat('小明家的小貓')
cat1.drink()
cat1.cry()
繼承實例

因此,對於面向對象的繼承來講,其實就是將多個類共有的方法提取到父類中,子類僅需繼承父類而沒必要一一實現每一個方法。

注:除了子類和父類的稱謂,你可能看到過 派生類 和 基類 ,他們與子類和父類只是叫法不一樣而已。

若是子類和父類都存在相同名稱的方法,子類對象優先調用子類中的方法,父類對象優先調用父類的方法

 

那麼問題又來了,多繼承呢?

  • 是否能夠繼承多個類
  • 若是繼承的多個類每一個類中都定了相同的函數,那麼那一個會被使用呢?

一、Python的類能夠繼承多個類,Java和C#中則只能繼承一個類

二、Python2.7中的類若是繼承了多個類,那麼其尋找方法的方式有兩種,分別是:深度優先廣度優先

 

Python中經典類和新式類的區別:

  區別主要體如今繼承上:

    Python的類能夠繼承多個類,Java和C#中則只能繼承一個類

    Python的類若是繼承了多個類,那麼其尋找方法的方式有兩種

        當類是經典類時,多繼承狀況下,會按照深度優先方式查找

        當類是新式類時,多繼承狀況下,會按照廣度優先方式查找

簡單點說就是:經典類是縱向查找,新式類是橫向查找

以下例:

#!usr/bin/env python
# -*- coding:utf-8 -*-
class Life():
      def daily(self):
          print "繁衍"
  
class Animal(Life):
      def daily(self):
          print ""
          print ""
          print ""
          print ""
 
class Puru(Life):
     def __init__(self):
         pass
 
class cat(Puru,Animal):
     def __init__(self):
         print "喵喵"
 
a = cat()
a.daily()

 # 執行結果是:
 # 喵喵
 # 繁衍
python2.7經典類 深度查找
#!usr/bin/env python
# -*- coding:utf-8 -*-

class Life(object):
     def daily(self):
         print "繁衍"

class Animal(Life):
     def daily(self):
         print ""
         print ""
         print ""
         print ""

class Puru(Life):
     def __init__(self):
         pass

class cat(Puru,Animal):
     def __init__(self):
         print "喵喵"

a = cat()
a.daily()

# 執行結果是:
# 喵喵
#
#
#
#
python2.7新式類 廣度查找

經典類和新式類,從字面上能夠看出一個老一個新,新的必然包含了不少的功能,也是以後推薦的寫法,從寫法上區分的話,若是 當前類或者父類繼承了object類,那麼該類即是新式類,不然即是經典類。

 

三、python3中再也不區分經典類和新式類,只有一種查找方式

 

面向對象之多繼承易錯點,函數中調用函數一樣按照一樣是按照上圖對象所在類的順序查找:
#!usr/bin/env python
# -*- coding:utf-8 -*-
class A:
    def f1(self):
        print("A")
    def Bar(self):
        self.f1()
class B(A):
    def f1(self):
        print("B")
class C:
    def f1(self):
        print("C")
class D(B,C):
    pass

d = D()
d.Bar()  #B,在執行self.f1()時,由於是D建立的對象,因此也是按照D B A C的順序查找的
調用順序易錯點

 子類執行父類構造方法的兩種方式:

#!usr/bin/env python
# -*- coding:utf-8 -*-
class Animal:
    def __init__(self):
        print('A構造方法')
        self.ty = "動物"
    def aaa(self):
        print("aaa")
class Cat(Animal):
    def __init__(self):
        print('B構造方法')
        self.n = ''
        #執行父類的構造方法,這樣系統會按照上圖的規則去父類找init構造方法,因此建議此種方法
        super(Cat,self).__init__()
        #或者用下面方法執行,此種方法隨意性比較強,容易混亂
        #Animal.__init__(self)
b = Cat()
# B構造方法
# A構造方法
子類執行父類構造方法

 補充:

子類調用父類的構造方法__init__()的兩種方法:

 

#!/ufr/bin/env python
# -*- coding:utf-8 -*-

class Animal:
    def __init__(self):
        print('A構造方法')
        self.ty = '動物'

class Cat(Animal):
    def __init__(self):
        print('B構造方法')
        self.n = ""
        super(Cat, self).__init__()  #第一種調用父類的構造方法,推薦這種使用方法,按照python的規則(順序)去調用
        #Animal.__init__(self) #第二種調用父類的構造方法

c = Cat()
print(c.__dict__)
#結果:
# B構造方法
# A構造方法
#{'n': '貓', 'ty': '動物'}

 

 利用反射導入模塊、查找類、建立對象、查找字段

 

 

 

 

3、多態 

 Pyhon不支持Java和C#這一類強類型語言中多態的寫法,由於python的變量是不區分類型的,因此python原生支持多態,以下例:

#!usr/bin/env python
# -*- coding:utf-8 -*-
class C1:
    def f1(self):
        print('C1')
class C2:
    def f1(self):
        print('C2')

def f2(arg):
    arg.f1()

c1 = C1()
c2 = C2()
f2(c1) #C1
f2(c2) #C2
多態

 練習實例:

#!usr/bin/env python
# -*- coding:utf-8 -*-
class Weapon:
    def __init__(self,name,limit_level,attack,duration):
        self.name = name  #武器名字
        self.limit_level = limit_level  #等級限制
        self.attack = attack #攻擊
        self.duration = duration  #持久 耐久

class Role:  #角色
    def __init__(self,name,blood,base_attack = 100):
        self.name = name   #角色名字
        self.blood = blood   #
        self.base_attack = base_attack  #基礎攻擊



class Magic(Role):  #魔法師
    def magic_attack(self,target,weapon):
        """魔法攻擊,target爲攻擊目標,需傳入Role的子類對象,weapon,需傳入Weapon對象"""
        target.blood -= (weapon.attack + self.base_attack)  #目標血量下降=攻擊方的基礎攻擊+攻擊方的武器攻擊

magic1 = Magic('笑熬漿糊',3000)
scarecrow1 = Role('稻草人',500,50)
mofazhang = Weapon('魔法杖',10,50,100)

magic1.magic_attack(scarecrow1,mofazhang) #傳入被攻擊對象和使用武器
print(scarecrow1.blood)
magic1.magic_attack(scarecrow1,mofazhang)
print(scarecrow1.blood)
傳奇模仿

擴展:

重載:類中的方法,方法名相同,方法的個數不一樣,python是不支持重載的,C# JAVA語言中支持重載

重寫:子類集成父類能夠重寫方法,子類對象調用方法的時候優先調用的是子類的方法 

4、靜態字段、靜態方法、類方法、特性(屬性)

一、靜態字段存在的意義:當類中具備相同字段和值的時候,若是在對象中設置須要每一個對象都須要賦值,例如:

靜態字段儘可能用類去調用,類的方法用對象去調用

#!/ufr/bin/env python
# -*- coding:utf-8 -*-

class Province:
    country = "China"  #建立靜態字段,靜態字段存儲在類中
    def __init__(self,name):
        self.name = name  #建立普通字段,普通字段存儲在對象中
    def print_name(self):
        print('%s' %(self.name))
shandong = Province('山東省')
hebei = Province("河北省")
shandong.print_name()

print(hebei.country)  #調用靜態字段的第1中方法
print(Province.country)  #調用靜態字段的第2種方法,推薦使用這種,原則是誰的成員誰調用

Province.print_name(shandong)  #調用類的方法的第1種方法
shandong.print_name()  #調用類的方法的第2種方法,推薦使用這種,原則類的方法由對象調用

 

靜態字段、靜態方法、類方法實例:

#!usr/bin/env python
# -*- coding:utf-8 -*-
class Province:
    country = "China"  #建立靜態字段,靜態字段存儲在類中
    def __init__(self,name):
        self.name = name  #建立普通字段,普通字段存儲在對象中

    def print_name(self):
        print('%s' %(self.name))

    @staticmethod    #靜態方法,靜態方法至關於普通函數
    def static_method(args):  #注意靜態方法沒有self
        print(args)

    @classmethod   #類方法
    def class_method(cls):  #類方法必須有cls參數,代指類
        cls.static_method(cls.country)  #能夠直接調用類的靜態方法,把靜態字段傳入

shandong = Province('山東省')
hebei = Province("河北省")
#調用類的普通方法的兩種方式
shandong.print_name()
Province.print_name(hebei)  #能夠用這種方式調用方法

#調用類的靜態方法的兩種方式
Province.static_method('類調用靜態方法')
shandong.static_method('shandong對象調用靜態方法')

#調用靜態字段的兩種方法
print(Province.country)
print(shandong.country)

#類的方法有兩種調用方式
Province.class_method()
shandong.class_method()
#總結:雖然有兩種方式調用,但潛規則是:
#一、對象調用:類中的方法、普通字段
#二、由類調用:靜態字段、靜態方法、類方法
靜態字段、靜態方法、類方法

 二、特性(屬性)

#!usr/bin/env python
# -*- coding:utf-8 -*-
class Province:
    def __init__(self,name):
        self.name = name

    @property  #特性(屬性),只能傳遞self參數;調用時不用加括號,即以字段的形式調用
    def county(self):
        if self.name == "山東省":
            return ["五蓮縣","莒縣","東港區"]
        else:
            return["未知"]

shandong = Province("山東省")
re = shandong.county  #特性(屬性)的調用方法
print(re)
特性(屬性)實例
#!usr/bin/env python
# -*- coding:utf-8 -*-
class Province:
    def __init__(self,name):
        self.name = name
        if self.name == "山東省":
            self.li = ["五蓮縣","莒縣","東港區"]
        else:
            self.li = ["未知"]

    @property  #特性(屬性),只能傳遞self參數;調用時不用加括號,即以字段的形式調用
    def county(self):
        return self.li
    @county.setter  #當設置特性(屬性)時調用此函數
    def county(self,value):
        self.li = value
shandong = Province("山東省")
re1 = shandong.county  #特性(屬性)的調用方法
print(re1)
re2 = shandong.county = ["日照市","濟南市"] #['日照市', '濟南市']
print(re2)
改變特性(屬性)值的方法

 成員總結,類的成員有:

對象中: 通常字段、通常方法

類中:靜態字段、靜態方法、類方法、特性(屬性)

其實就是三大類:字段、方法、特性

那麼用類仍是對象調用呢:只記住一句話,傳self的用對象調用,其餘的用類調用

三、面向對象之成員修飾符

成員的前面加兩個下劃線(__)表示私有的,只能在類的內部調用,外部不能調用,只能在成員所屬類的內部能訪問,其子類和對象都是不能訪問的,字段和方法都是適用的

1)靜態字段的私有修飾符

#!usr/bin/env python
# -*- coding:utf-8 -*-
class Province:
    __country = 'China'
    def __init__(self):
        pass
    def print_country(self):
        return Province.__country

p = Province()
#print(Province.__country)  #此句報錯由於__country是私有靜態字段
print(p.print_country())
靜態字段修飾符

 成員修飾符:全部成員加兩個下劃線(__)都可變爲私有的,變爲私有的後只能在本類中被訪問,其繼承類中也不能訪問。

2)若是想調用私有字段或方法怎麼辦呢?能夠在字符或方法名前面加(_類名.)的方法進行調用,但通常不建議這麼作,例如:

#!usr/bin/env python
# -*- coding:utf-8 -*-
class Province:
    __country = 'China'
    def __init__(self,name):
        self.__name = name
    def print_country(self):
        return Province.__country

p = Province("山東")
print(p._Province__name)  #山東
外部調用私有方法或字段

 四、類的特殊成員

1)__init__()

2)__del__()

3)__call__(self),類中的call的特殊方法,能夠用對象加括號執行。(對象())

#!usr/bin/env python
# -*- coding:utf-8 -*-
class Foo:
    def __init__(self):
        print('__init__')
    def __call__(self,*args,**kwargs):
        print('__call__')
foo = Foo()
foo()  #輸出:'__call__'。對象加括號,實際是執行的__call__()函數。兩句合起來:Foo()()

 4)getitem setitm delitem

foo["key"]  調用 getitem  ;  foo[1:3] 調用getitem ; python2.x中是調用的getslice

foo["key"] = value 調用setitem ; foot[1:3] = [11,22,33]調用的是setitem;python2.x中調用的是setslice

del foo["key"] 調用delitem;  del foor[1:3] 調用的是delitem ; python2.x中調用的是delslice

例如:

#!usr/bin/env python
# -*- coding:utf-8 -*-
class Foo:
    def __init__(self):
        pass
    def __getitem__(self,item):  #對應的是:foo["key"]
        print(item)
    def __setitem__(self, key, value): #對應的是:foo["key"] = "value"
        print("%s:%s" %(key,value))
    def __delitem__(self, key):   #對應的是:del foo["key"]
        print('delte this' + key)

foo = Foo()
foo['key']
foo["key"] = "value"
del foo["key"]
字典方式的執行方法
#!usr/bin/env python
# -*- coding:utf-8 -*-
class Foo:
    def __init__(self):
        pass
    def __getitem__(self,item):  #對應的是:foo[1:20:2]
        print(item.indices(100)) #最大值爲100,將slice對象轉爲元組(1, 20, 2)
    def __setitem__(self, key, value): #對應的是:foo[1:3] = [11,22]
        emp = key.indices(100)
        print(emp,value)
    def __delitem__(self, key):   #對應的是:del foo[1:3]
        print(key.indices(100))

foo = Foo()
foo[1:20:2]  #打印:(1, 20, 2)
foo[1:3] = [11,22] #打印輸出:(1, 3, 1) [11, 22]
del foo[1:3] #打印輸出:(1, 3, 1)
#slice.indices()
切片特殊方法用法

 5)類的特殊成員之__dict__  ,查看對象或類中的成員

#!usr/bin/env python
# -*- coding:utf-8 -*-
class Foo:
    def __init__(self):
        self.name = 'sunshuhai'
    def hello(self):
        pass
foo = Foo()
print(foo.__dict__)  #查看對象中的成員
print(Foo.__dict__)  #查看類中的成員
__dict__

 6)特殊成員之__iter__(self)方法

當for循環類的對象時,實際執行的就是類中的__iter__(self)方法

#!usr/bin/env python
# -*- coding:utf-8 -*-
class Foo:
    def __iter__(self):
        yield 1
        yield 2
        yield 3

foo = Foo()
for i in foo:  #當循環對象時,實際執行的是特殊方法__iter__(self)
    print(i)
特殊方法__iter__(self)

7)類的特殊成員之__str__(self)

在用print打印對象,或將對象轉爲字符串時,會自動執行__str__(self)方法

#!usr/bin/env python
# -*- coding:utf-8 -*-
class Foo:
    def __init__(self,ef):
        self.ef = ef
    def __str__(self):
        return self.ef

exception = Foo('出錯了。。。。')
print(exception)  #出錯了。。。。,實際調用的是__str__(self)方法
類的特殊方法__str__(self)

8)瞭解:類的特殊成員之new和metaclass

類是由對象Type建立的 

相關文章
相關標籤/搜索