Python基礎知識:類

初級篇

  • 面向過程:根據業務邏輯從上到下寫壘代碼python

  • 函數式:將某功能代碼封裝到函數中,往後便無需重複編寫,僅調用函數便可c++

  • 面向對象:對函數進行分類和封裝,讓開發「更快更好更強...」程序員

一、面向對象三大特性:封裝、繼承、多態。數據庫

  • 封裝:將內容封裝到某處,從某處調用被封裝的內容;編程

  • 繼承:子類能夠繼承父類的全部內容,分爲單繼承和多繼承;設計模式

    • 當類是經典類(不繼承object)時,多繼承狀況下,會按照深度優先方式查找,即左邊一條道走到黑,一直到共同的父類,再去右邊找;app

    • 當類是新式類(默認繼承object)時,多繼承狀況下,會按照廣度優先方式查找,即左邊到共同父類以前,再去右邊找,直到共同父類;框架

  • 多態:由不一樣的類實例化獲得的對象,調用同一個方法,執行的邏輯不一樣。dom

二、建立類ide

  • class ClassName()--建立類,類的命名規則爲駝峯法,每一個單詞的首字母必須大寫;小寫的名稱指根據類建立的實例(對象);
  • Python2.7中建立類時,須要在括號內包含object,如class ClassName(object)
  • 類中的函數稱爲方法,有關函數的一切都適用於方法,惟一的差異在於調用方法的方式;
  • __init__()這是一個特殊的方法,稱爲構造方法,每當你根據類建立新的實例時,Python都會自動運行它;開頭和末尾各有兩個下劃線,這是一種約定,旨在避免默認方法和普通方法發生名稱衝突;
class Dog():
    '''一次模擬小狗的簡單嘗試'''
    def __init__(self,name,age):
        '''初始化屬性name和age'''
        self.name = name
        self.age = age
    def sit(self):
        '''模擬小狗被命令時蹲下'''
        print(self.name.title() + ' is now sitting.')
    def roll_over(self):
        '''模擬小狗被命令時打滾'''
        print(self.name.title() + ' rolled over.')
my_dog = Dog('holiday',3)
print("My dog's name is " + my_dog.name.title() + '.')
print("My dog's age is " + str(my_dog.age) + '.')
#用句點法來調用Dog類中定義的任何方法
my_dog.sit()
my_dog.roll_over()

三、類中的每一個屬性都要有初始值,哪怕這個值是0或空字符,在有些狀況下,能夠設置默認值,在__init__()內指定初始值,若是你對某個屬性這麼作了,就無需包含爲它提供初始值的形參。

  • 三種方法修改屬性值:一、直接修改;二、經過方法修改;三、經過增量修改
#建立一個餐館類,並修改屬性值
class Restaurant():
    def __init__(self,restaurant_name,cuisine_type):
        self.restaurant_name = restaurant_name
        self.cuisine_type = cuisine_type
        self.number_served = 0    #設置屬性默認值
    def describe_restaurant(self):
        print("The name of restaurant is %s."%self.restaurant_name)
        print("The cuisine type of restaurant is %s."%self.cuisine_type)
        print("[%s] people have dined in this restaurant."%self.number_served)
    def set_number_served(self,number):  # 2經過方法修改屬性值
        self.number_served = number
    def increment_number_served(self,increment_num):  #3經過增量修改屬性值
        self.number_served += increment_num
        '''這個增量就是餐館天天的就餐人數'''
        print('I think the restaurant serves %s people a day.'%increment_num)
    def open(self):
        print("The restaurant is open!")
restaurant = Restaurant('KFC','fast food')
restaurant.number_served = 10 #1直接修改屬性值
restaurant.describe_restaurant()
restaurant.set_number_served(200)
restaurant.describe_restaurant()
restaurant.increment_number_served(300)
restaurant.describe_restaurant()
View Code

四、單繼承:一個類繼承另外一個類時,它將自動獲取另個一個類的全部屬性和方法,原有的稱爲父類,也叫基類,新類稱爲子類,也叫派生類;同時子類還能夠定義本身特有的屬性和方法;若是父類和子類有相同的方法,子類優先執行本身的方法。

  建立子類時,Python首先要完成的就是爲父類的全部屬性賦值;super是一個特殊的函數,幫助子類和父類關聯起來,父類也叫superclass,名稱所以而來。

  Python2.7中函數super()須要兩個實參:子類名和對象self。

#子類冰淇淋店繼承父類餐館
class Restaurant():
    def __init__(self,restaurant_name,cuisine_type):
        self.restaurant_name = restaurant_name
        self.cuisine_type = cuisine_type
    def describe_restaurant(self):
        print("The name of restaurant is %s."%self.restaurant_name)
        print("The cuisine type of restaurant is %s."%self.cuisine_type)
class IceCreamStand(Restaurant):
    def __init__(self,restaurant_name,cuisine_type):
        super().__init__(restaurant_name,cuisine_type)
        self.flavors = []
    def show_flavors(self):
        print("The menu of icecreamstand is as follows:")
        for flavor in self.flavors:
            print('\t' + flavor)
icecreamstand = IceCreamStand('Ice And Snow','icecream')
icecreamstand.flavors = ['a','b','c','d']
icecreamstand.show_flavors()

五、多繼承:class 類(類1,類2);若是類1和類2有相同的方法,優先執行類1的方法;

  • 若是類1和類2沒有共同的父類:一條道走到黑

  • 若是類1和類2有共同的父類:第一條路只走到共同父類以前,再去走第二條路,最後再去找共同的父類;
  • Python2中的類默認不繼承object類,這中狀況會一條路走到黑,直到頂端,繼承Object以後就不會走到黑;

  • 複雜的繼承關係:

 

六、將實例用做屬性

#將Privileges實例用做Admin類的一個屬性
class User():
    def __init__(self,first_name,last_name,age):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age
        self.login_attempts = 0
    def describe_user(self):
        print("User's first name is %s."%self.first_name)
        print("User's last name is %s."%self.last_name)
        print("User's age is %d."%self.age)
        print("User logged in %d times."%self.login_attempts)
    def increment_login_attempts(self):
        self.login_attempts += 1
    def reset_login_attempts(self):
        self.login_attempts = 0
    def greet_user(self):
        print("Hello " + self.last_name + ' ' + self.first_name +
              ",long time no see,are you OK?")
class Admin(User):
    def __init__(self,first_name,last_name,age):
        super().__init__(first_name,last_name,age)
        self.privileges = Privileges()
class Privileges():
    def __init__(self):
        self.privileges = ['can add post','can delete post','can ban user']
    def show_privileges(self):
        print('Administrator have the following privileges:')
        for privilege in self.privileges:
            print('\t'+privilege)
user = User('james','lebran',34)
user.increment_login_attempts()
user.describe_user()
user.reset_login_attempts()
user.describe_user()
admin = Admin('james','lebran',34)
admin.privileges.show_privileges()
View Code

七、導入類

  • 方法同調用模塊中的函數同樣,模塊中能夠存放單個類或者多個類,使用import或者from...import..,*表示調出模塊中全部類;
  • 在使用pickle模塊將對象保存到文件時,若是想在另個一個py文件中load該文件的對象,須要先導入對應的類;
  • 有時候,須要將類分散到多個模塊中,以避免模塊太大,或在同一模塊中存儲不相關的類;將類存儲在多個模塊時,你可能會發現一個模塊中的類依賴於另外一個模塊中的類,這種狀況下,可在前一個模塊中導入必要的類。

八、有序字典

  • 第一種方法: 定義一個新類,繼承字典類
class MyDict(dict):
    def __init__(self):
        self.li = []
        #執行字典的初始化方法
        super(MyDict,self).__init__()
    def __setitem__(self, key, value):
        #執行字典的設置方法,將k,v添加到字典
        self.li.append(key)
        super(MyDict,self).__setitem__(key, value)
    def __str__(self):
        temp_list = []
        for key in self.li:
            value = self.get(key)
            temp_list.append("'%s:'%s"%(key,value))
        temp_str = '{' + ','.join(temp_list) + '}'
        return temp_str
obj = MyDict()
obj['k1'] = 123
obj['k2'] = 356
print(obj)
  • 第二種方法:collections模塊中的一個類OrderedDict(),記錄字典中鍵值對的添加順序,少許數據看不出來效果;
from collections import OrderedDict
favor_lang = OrderedDict()
favor_lang['james'] = 'c'
favor_lang['paul'] = 'c++'
favor_lang['alice'] = 'python'
new_dic = {}
for k,v in favor_lang.items():
    new_dic[k] = v
print(new_dic)

九、random模塊包含以各類方式生成隨機數的函數,randint()隨機返回一個位於指定範圍內的整數,範圍兩端的數字也會返回;

#搖骰子
from random import randint
class Die():
    def __init__(self,sides=6):
        self.sides = sides
    def roll_die(self):
        print(randint(1,self.sides))
die = Die(6)  
die.roll_die()  

十、練習題

#汽車-電動汽車-電池,給電池類添加一個更新電池容量的方法
class Car():
    def __init__(self,make):
        self.make = make
        print('I have an %s.'%self.make)
class ElectricCar(Car):
    def __init__(self,make):
        super().__init__(make)
        self.battery = Battery()
class Battery():
    def __init__(self,battery_size=70):
        self.battery_size = battery_size
    def get_range(self):
        if self.battery_size == 70:
            range = 240
        elif self.battery_size == 85:
            range = 270
        print('This car can go approximately %d miles on a full charge.'%range)
    def upgrade_battery(self):
        if self.battery_size != 85:
            self.battery_size = 85
my_car = Car('audi')
electric_car = ElectricCar('tesla')
electric_car.battery.get_range()
electric_car.battery.upgrade_battery()
electric_car.battery.get_range()
my_battery = Battery(85)
my_battery.get_range()
View Code

 十一、面向對象初級知識的介紹,總結以下:

  • 面向對象是一種編程方式,此編程方式的實現是基於對  和 對象 的使用
  • 類 是一個模板,模板中包裝了多個「函數」供使用
  • 對象,根據模板建立的實例(即:對象),實例用於調用被包裝在類中的函數
  • 面向對象三大特性:封裝、繼承和多態

問答專區

問題一:什麼樣的代碼纔是面向對象?

答:從簡單來講,若是程序中的全部功能都是用 類 和 對象 來實現,那麼就是面向對象編程了。

問題二:函數式編程 和 面向對象 如何選擇?分別在什麼狀況下使用?

答:須知:對於 C# 和 Java 程序員來講不存在這個問題,由於該兩門語言只支持面向對象編程(不支持函數式編程)。而對於 Python 和 PHP 等語言卻同時支持兩種編程方式,且函數式編程能完成的操做,面向對象均可以實現;而面向對象的能完成的操做,函數式編程不行(函數式編程沒法實現面向對象的封裝功能)。

因此,通常在Python開發中,所有使用面向對象 或 面向對象和函數式混合使用

面向對象的應用場景:

  1. 多函數需使用共同的值,如:數據庫的增、刪、改、查操做都須要鏈接數據庫字符串、主機名、用戶名和密碼
  2. 須要建立多個事物,每一個事物屬性個數相同,可是值的需求
    如:張3、李4、楊五,他們都有姓名、年齡、血型,但其都是不相同。即:屬性個數相同,但值不相同

問題三:類和對象在內存中是如何保存?

答:類以及類中的方法在內存中只有一份,而根據類建立的每個對象都在內存中須要存一份,大體以下圖:

根據類建立對象時,對象中除了封裝 name 和 age 的值以外,還會保存一個類對象指針,該值指向當前對象的類。

進階篇

  • 類的成員能夠分爲三大類:字段、方法和屬性

注:全部成員中,只有普通字段的內容保存對象中,即:根據此類建立了多少對象,在內存中就有多少個普通字段。而其餘的成員,則都是保存在類中,即:不管對象的多少,在內存中只建立一份。

一、字段:普通字段和靜態字段,他們在定義和使用中有所區別,而最本質的區別是內存中保存的位置不一樣

  • 普通字段屬於對象,普通字段在每一個對象中都要保存一份,只有類沒有對象,內存中就沒有普通字段;
  • 靜態字段屬於類,靜態字段在內存中只保存一份;
  • 普通字段只能用對象訪問,只有Python中靜態字段能夠用類和對象同時訪問,最好不要用對象訪問靜態字段,以避免往後代碼出錯。
  • 應用場景: 經過類建立對象時,若是每一個對象都具備相同的字段,那麼就使用靜態字段;
class Province:
    # 靜態字段
    country = '中國'
    def __init__(self, name):
        # 普通字段
        self.name = name
# 直接訪問普通字段
obj = Province('河北省')
print obj.name
# 直接訪問靜態字段
Province.country

 二、方法:普通方法、靜態方法和類方法,三種方法在內存中都歸屬於類,區別在於調用方式不一樣。

  • 普通方法:由對象調用;至少一個self參數;執行普通方法時,自動將調用該方法的對象賦值給self
  • 類方法:由調用; 至少一個cls參數;執行類方法時,自動將調用該方法的類名賦值給cls
  • 靜態方法:由調用;參數無關緊要;
  • 類方法和靜態方法Python中也能夠用對象調用,可是儘可能不要用;
class Foo:
    def __init__(self, name):
        self.name = name
    def ord_func(self):
        """ 定義普通方法,至少有一個self參數 """
        # print(self.name)
        print('普通方法')
    @classmethod
    def class_func(cls):
        """ 定義類方法,至少有一個cls參數 """
        print('類方法')
    @staticmethod
    def static_func():
        """ 定義靜態方法 ,無默認參數"""
        print('靜態方法')
# 調用普通方法
f = Foo()
f.ord_func()
# 調用類方法
Foo.class_func()
# 調用靜態方法
Foo.static_func()

相同點:對於全部的方法而言,均屬於類(非對象)中,因此,在內存中也只保存一份。

不一樣點:方法調用者不一樣、調用方法時自動傳入的參數不一樣。

三、屬性

  • Python中的屬性實際上是普通方法的變種,具備方法的寫做形式,具備字段訪問形式。對於屬性,有如下兩個知識點:

  a、屬性的基本使用

#屬性的基本使用
# ############### 定義 ###############
class Foo:
    def func(self):
        pass
    # 定義屬性
    @property
    def prop(self):
        pass
# ############### 調用 ###############
foo_obj = Foo()
foo_obj.func()
foo_obj.prop   #調用屬性

由屬性的定義和調用要注意一下幾點:

  • 定義時,在普通方法的基礎上添加 @property 裝飾器;
  • 定義時,屬性僅有一個self參數
  • 調用時,無需括號
               方法:foo_obj.func()
               屬性:foo_obj.prop

屬性存在乎義是:訪問屬性時能夠製造出和訪問字段徹底相同的假象;屬性由方法變種而來,若是Python中沒有屬性,方法徹底能夠代替其功能。

實例:對於主機列表頁面,每次請求不可能把數據庫中的全部內容都顯示到頁面上,而是經過分頁的功能局部顯示,因此在向數據庫中請求數據時就要顯示的指定獲取從第m條到第n條的全部數據(即:limit m,n),這個分頁的功能包括:

  • 根據用戶請求的當前頁和總數據條數計算出 m 和 n
  • 根據m 和 n 去數據庫中請求數據 
# ############### 定義 ###############
class Pager:   
    def __init__(self, current_page):
        # 用戶當前請求的頁碼(第一頁、第二頁...)
        self.current_page = current_page
        # 每頁默認顯示10條數據
        self.per_items = 10 

    @property
    def start(self):
        val = (self.current_page - 1) * self.per_items
        return val

    @property
    def end(self):
        val = self.current_page * self.per_items
        return val
# ############### 調用 ###############
p = Pager(1)
p.start 就是起始值,即:m
p.end   就是結束值,即:n
View Code

從上述可見,Python的屬性的功能是:屬性內部進行一系列的邏輯計算,最終將計算結果返回。

  b、屬性的兩種定義方式:

  • 裝飾器 即:在類的普通方法上應用裝飾器;
  • 靜態字段 即:在類中定義值爲property對象的靜態字段;

 咱們知道Python中的類有經典類和新式類,新式類的屬性比經典類的屬性豐富。( 若是類繼object,那麼該類是新式類 );

#經典類,具備一種@property裝飾器(如上一步實例)
# ############### 定義 ###############    
class Goods:
    @property
    def price(self):
        return "wupeiqi"
# ############### 調用 ###############
obj = Goods()
result = obj.price  # 自動執行 @property 修飾的 price 方法,並獲取方法的返回值
View Code

 

#新式類,具備三種@property裝飾器
# ############### 定義 ###############
class Goods(object):
    @property
    def price(self):
        print '@property'
    @price.setter
    def price(self, value):
        print '@price.setter'
    @price.deleter
    def price(self):
        print '@price.deleter'
# ############### 調用 ###############
obj = Goods()
obj.price    # 自動執行 @property 修飾的 price 方法,並獲取方法的返回值
obj.price = 123    # 自動執行 @price.setter 修飾的 price 方法,並將  123 賦值給方法的參數
del obj.price    # 自動執行 @price.deleter 修飾的 price 方法
View Code

注:經典類中的屬性只有一種訪問方式,其對應被 @property 修飾的方法;新式類中的屬性有三種訪問方式,並分別對應了三個被@property、@方法名.setter、@方法名.deleter修飾的方法;因爲新式類中具備三種訪問方式,咱們能夠根據他們幾個屬性的訪問特色,分別將三個方法定義爲對同一個屬性:獲取、修改、刪除;

class Goods(object):

    def __init__(self):
        # 原價
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    @property
    def price(self):
        # 實際價格 = 原價 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    @price.setter
    def price(self, value):
        self.original_price = value

    @price.deltter
    def price(self, value):
        del self.original_price

obj = Goods()
obj.price         # 獲取商品價格
obj.price = 200   # 修改商品原價
del obj.price     # 刪除商品原價
View Code
  • 當使用靜態字段的方式建立屬性時,經典類和新式類無區別
class Foo:

    def get_bar(self):
        return 'wupeiqi'

    BAR = property(get_bar)

obj = Foo()
reuslt = obj.BAR        # 自動調用get_bar方法,並獲取方法的返回值
print reuslt
View Code

property的構造方法中有個四個參數:

  • 第一個參數是方法名,調用 對象.屬性 時自動觸發執行方法
  • 第二個參數是方法名,調用 對象.屬性 = XXX 時自動觸發執行方法
  • 第三個參數是方法名,調用 del 對象.屬性 時自動觸發執行方法
  • 第四個參數是字符串,調用 對象.屬性.__doc__ ,此參數是該屬性的描述信息
class Foo:

    def get_bar(self):
        return 'wupeiqi'

    # *必須兩個參數
    def set_bar(self, value): 
        return return 'set value' + value

    def del_bar(self):
        return 'wupeiqi'

    BAR = property(get_bar, set_bar, del_bar, 'description...')

obj = Foo()

obj.BAR              # 自動調用第一個參數中定義的方法:get_bar
obj.BAR = "alex"     # 自動調用第二個參數中定義的方法:set_bar方法,並將「alex」看成參數傳入
del Foo.BAR          # 自動調用第三個參數中定義的方法:del_bar方法
obj.BAE.__doc__      # 自動獲取第四個參數中設置的值:description...
View Code

 注意:Python WEB框架 Django 的視圖中 request.POST 就是使用的靜態字段的方式建立的屬性;因此,定義屬性共有兩種方式,分別是【裝飾器】和【靜態字段】,而【裝飾器】方式針對經典類和新式類又有所不一樣。

 四、類成員的修飾符

類的全部成員在上一步驟中已經作了詳細的介紹,對於每個類的成員而言都有兩種形式:

  • 公有成員,在任何地方都能訪問
  • 私有成員,只有在類的內部才能方法

 私有成員和公有成員的定義不一樣:私有成員命名時,前兩個字符是下劃線。(特殊成員除外,例如:__init__、__call__、__dict__等)

class C:
 
    def __init__(self):
        self.name = '公有字段'
        self.__foo = "私有字段"
View Code

私有成員和公有成員的訪問限制不一樣

靜態字段

  • 公有靜態字段:類能夠訪問;類內部能夠訪問;派生類中能夠訪問
  • 私有靜態字段:僅類內部能夠訪問;
class C:

    name = "公有靜態字段"

    def func(self):
        print C.name

class D(C):

    def show(self):
        print C.name


C.name         # 類訪問

obj = C()
obj.func()     # 類內部能夠訪問

obj_son = D()
obj_son.show() # 派生類中能夠訪問
公有靜態字段
class C:

    __name = "公有靜態字段"

    def func(self):
        print C.__name

class D(C):

    def show(self):
        print C.__name


C.__name       # 類訪問            ==> 錯誤

obj = C()
obj.func()     # 類內部能夠訪問     ==> 正確

obj_son = D()
obj_son.show() # 派生類中能夠訪問   ==> 錯誤
私有靜態字段

普通字段

  • 公有普通字段:對象能夠訪問;類內部能夠訪問;派生類中能夠訪問
  • 私有普通字段:僅類內部能夠訪問;

ps:若是想要強制訪問私有字段,能夠經過 【對象._類名__私有字段明 】訪問(如:obj._C__foo),不建議強制訪問私有成員。

方法、屬性的訪問於上述方式類似,即:私有成員只能在類內部使用

五、類的特殊成員

  • __方法名__,這種先後有雙下劃線的方法爲構造方法,還有一種方法叫析構方法,Python內部回收機制會在沒有調用類的任何成員的時候,把內存清掉,在清除以前會執行一個析構方法__del__( )
  •   __doc__

  表示類的描述信息

  •  __module__ 和  __class__ 

  __module__ 表示當前操做的對象在那個模塊

  __class__     表示當前操做的對象的類是什麼

  •  __init__

  構造方法,經過類建立對象時,自動觸發執行。

  •  __del__

  析構方法,當對象在內存中被釋放時,自動觸發執行。

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

  •  __call__

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

注:構造方法的執行是由建立對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象後加括號觸發的,即:對象() 或者 類()()

class Foo:

    def __init__(self):
        pass
    
    def __call__(self, *args, **kwargs):

        print('__call__')


obj = Foo() # 執行 __init__
obj()       # 執行 __call__
  •  __dict__

  類或對象中的全部成員

class Province:

    country = 'China'

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

    def func(self, *args, **kwargs):
        print('func')

# 獲取類的成員,即:靜態字段、方法、
print Province.__dict__
# 輸出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None}

obj1 = Province('HeBei',10000)
print obj1.__dict__
# 獲取 對象obj1 的成員
# 輸出:{'count': 10000, 'name': 'HeBei'}
  •  __str__

  若是一個類中定義了__str__方法,那麼在打印 對象 時,默認輸出該方法的返回值。

class Foo:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __str__(self):
        return '%s - %s' % (self.name,self.age)
#直接打印
obj = Foo('alex',23)
print(obj)
#執行str()函數,就會自動執行類中的__str__函數,並獲取返回值
ret = str(obj)
print(ret)
View Code
  •  __repr__

  對於一個object來講,__str__和__repr__都是返回對object的描述,只是,前一個的描述簡短而友好,後一個的描述,更細節複雜一些。__str__()用於顯示給用戶,而__repr__()用於顯示給開發人員,在終端不用print也會顯示repr的返回值,而str函數的返回值必須print才能看見。

  print(對象)時,若是找不到str方法,會執行repr方法代替輸出,若是兩個方法共存,仍是執行str方法。

  • __getitem__、__setitem__、__delitem__

用於索引操做,如字典。有兩種方法觸發以上函數,分別是字符串形式和切片形式;以上分別表示獲取、設置、刪除數據;

class Foo():
    def __getitem__(self, key):
        print(key)
    def __setitem__(self, key, value):
        print(key, value)
    def __delitem__(self, key):
        print(key)
#字符串方式
obj = Foo()
result = obj['k1']  # 自動觸發執行 __getitem__
obj['k2'] = 'charlie'  # 自動觸發執行 __setitem__
del obj['k1']  # 自動觸發執行 __delitem__
#輸出
# k1
# k2 charlie
# k1
#切片方式
class Foo1():
    def __getitem__(self, item):
        #item.start,item.stop,item.step
        print(type(item))
    def __setitem__(self, key, value):
        print(type(key), type(value))
    def __delitem__(self, key):
        print(type(key))
obj = Foo1()
ret = obj[1:4:2] # 自動觸發執行 __getitem__
obj[1:4] = [1,2] # 自動觸發執行 __setitem__
del obj[1:4]  # 自動觸發執行 __delitem__
#輸出
# <class 'slice'>
# <class 'slice'> <class 'list'>
# <class 'slice'>
View Code
  •  __iter__ 

用於迭代器,之因此列表、字典、元組能夠進行for循環,是由於類型內部定義了 __iter__

class Foo:
    def __init__(self, sq):
        self.sq = sq
    def __iter__(self):
        return iter(self.sq)
obj = Foo([11,22,33,44])
for i in obj:
    print(i)
#輸出11,22,33,44
#若是iter方法是一個生成器
class Foo:
    def __init__(self, sq):
        self.sq = sq
    def __iter__(self):
        yield 1
        yield 2
        yield 3
obj = Foo([11,22,33,44])
for i in obj:
    print(i)
#輸出1,2,3
  •  __new__ 和 __metaclass__

閱讀如下代碼:

class Foo:
    def __init__(self):
        pass
obj = Foo()   # obj是經過Foo類實例化的對象

上述代碼中,obj 是經過 Foo 類實例化的對象,其實,不只 obj 是一個對象,Foo類自己也是一個對象,由於在Python中一切事物都是對象。若是按照一切事物都是對象的理論:obj對象是經過執行Foo類的構造方法建立,那麼Foo類對象應該也是經過執行某個類的 構造方法 建立。

print type(obj) # 輸出:<class '__main__.Foo'>     表示,obj 對象由Foo類建立
print type(Foo) # 輸出:<type 'type'>              表示,Foo類對象由 type 類建立

因此,obj對象是Foo類的一個實例Foo類對象是 type 類的一個實例,即:Foo類對象 是經過type類的構造方法建立。那麼,建立類就能夠有兩種方式:

a). 普通方式

class Foo:
 
    def func(self):
        print('hello wupeiqi')

b).特殊方式(type類的構造函數)

def func(self):
    print('hello wupeiqi')
Foo = type('Foo',(object,), {'func': func})
#type第一個參數:類名
#type第二個參數:當前類的基類
#type第三個參數:類的成員

問題:類是由 type 類實例化產生,那麼問題來了,類默認是由 type 類實例化產生,type類中如何實現的建立類?類又是如何建立對象?

答:類中有一個屬性 __metaclass__,其用來表示該類由 誰 來實例化建立,因此,咱們能夠爲 __metaclass__ 設置一個type類的派生類,從而查看 類 建立的過程。

class MyType(type):

    def __init__(self, what, bases=None, dict=None):
        super(MyType, self).__init__(what, bases, dict)

    def __call__(self, *args, **kwargs):
        obj = self.__new__(self, *args, **kwargs)

        self.__init__(obj)

class Foo:

    __metaclass__ = MyType

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

    def __new__(cls, *args, **kwargs):
        return object.__new__(cls, *args, **kwargs)

# 第一階段:解釋器從上到下執行代碼建立Foo類
# 第二階段:經過Foo類建立obj對象
obj = Foo()

 六、isinstance()判斷對象是不是某個類的實例,這個類能夠是建立實例的類型或類的父類;issubclass()判斷一個類是不是另外一個類的子類

#判斷對象是不是某個類的實例
r = "abc"
print(isinstance(r,str))#True

七、主動執行父類的方法,第一種方法:super(子類,self).f1();第二種方法:F1.f1(self),不建議使用,瞭解就行;

class F1:
    def f1(self):
        print('f1.f1')
class F2(F1):
    def f1(self):
        #主動執行父類的fi
        super(F2,self).f1()
        #另外一種方法:F1.f1(self)
        print('f2.f1')
obj = F2()
obj.f1()
# f1.f1
# f2.f1

八、設計模式之單例模式

class Foo:
    #單例模式
    instance = None
    def __init__(self,name):
        self.name = name
    @classmethod
    def get_instance(cls):
        if cls.instance:
            return cls.instance
        else:
            obj = cls('alex')
            cls.instance = obj
            return obj
obj1 = Foo.get_instance()
print(obj1)
obj2 = Foo.get_instance()
print(obj2)
#兩個對象如出一轍
# <__main__.Foo object at 0x000000B059AC92E8>
# <__main__.Foo object at 0x000000B059AC92E8>
class F1:
    #普通模式
    def __init__(self,name):
        self.name = name
f1 = F1('alex')
print(f1)
f2 = F1('alex')
print(f2)
#普通模式,參數同樣時兩個對象也不同
# <__main__.F1 object at 0x0000003E04762400>
# <__main__.F1 object at 0x0000003E04762550>
相關文章
相關標籤/搜索