python面向對象編程

本篇內容:java

  •   一、反射
  •   二、面向對象編程
  •   三、面向對象三大特性
  •   四、類成員
  •   五、類成員修飾符
  •   六、類的特殊成員
  •   七、單例模式

反射

python中的反射功能是由如下四個內置函數提供:hasattr、getattr、setattr、delattr,改四個函數分別用於對對象內部執行:檢查是否含有某成員、獲取成員、設置成員、刪除成員。python

import commas同等於下面字符串導入模塊 inp = input("請輸入模塊名:") dd = __import__(inp) ret =dd.f1() print(ret)
經過字符串的形式導入模塊
#應用根據用戶輸入導入模塊
inp = input("請輸入模塊:") inp_func = input("請輸入執行的函數:") # __import__以字符串的形式導入模塊
moudle = __import__(inp) #getattr 用以去某個模塊中尋找某個函數
target_func = getattr(moudle,inp_func) relust = target_func() print(relust)
指定函數中執行指定函數
一、getattr
經過字符串的形式去某個模塊中尋找東西
import commas #去commas,尋找name變量,找不到返回none
target_func = getattr(commas ,"name",None) print(target_func)
demo
二、hasattr
經過字符串的形式去某個模塊中判斷東西是否存在
import commas #去commas模塊中尋找f1,有返回true,沒有返回none
target_func = hasattr(commas,"f1") print(target_func)
demo
三、setattr
經過字符串的形式去某個模塊中設置東西
import commas #去commas模塊中尋找name,有返回true,沒有返回none
target_func1 = hasattr(commas,"name") print(target_func1) #在內存裏往commas模塊中添加name = "zhangyanlin"
setattr(commas,"name","zhangyanlin") #在內存裏往commas模塊中建立函數
setattr(commas,"f3",lambda x: "zhen" if x >10 else "jia") #去commas模塊中尋找name,有返回true,沒有返回none
target_func = hasattr(commas,"name") print(target_func)
demo
四、delattr
import commas target_func = hasattr(commas,"f1") print(target_func) del_func = delattr(commas,"f1") target_func = hasattr(commas,"f1") print(target_func)
demo

  案例:程序員

'''
基於web框架實現路由功能 ''' url = str(input("請輸入URL:")) #輸入URL,先輸入模塊,後面加函數 target_moudle,target_func = url.split("/") # 用/把分割開,前面是模塊 後面是函數 moudle = __import__(target_moudle,fromlist=True) #導入模塊 if hasattr(moudle,target_func): #判斷模塊裏有這個函數 target_func = getattr(moudle,target_func) #找到那個函數 ret = target_func() #執行函數 print(ret) else: #不然報錯 print("404") 

 

class Foo:

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

    def login(self):
        print("登陸請按1:")

obj = Foo("zhangyanlin")
ret = getattr(obj,"name")
print(ret)
#反射
#以字符串的形式去對續航中操做成員
#反射:類,只能找類的成員
ret = hasattr(Foo,"login")
print(ret)

#反射:對象,既能夠找對象也能找類的成員
ret = hasattr(obj,"name")
print(ret)
ret = hasattr(obj,"login")
print(ret)
反射類實例

面向對象編程

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

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

 

一、建立類和對象數據庫

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

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

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

  • class是關鍵字,表示類
  • 建立對象,類名稱後加括號便可
# 建立類
class Foo:
     
    def Bar(self):
        print 'Bar'
 
    def Hello(self, name):
        print 'i am %s' %name
 
# 根據類Foo建立對象obj
obj = Foo()
obj.Bar()            #執行Bar方法
obj.Hello('wupeiqi') #執行Hello方法 

1、封裝框架

封裝,顧名思義就是將內容封裝到某個地方,之後再去調用被封裝在某處的內容。因此,在使用面向對象的封裝特性時,須要:ide

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

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

demo

第二步:從某處調用被封裝的內容調用被封裝的內容時,有兩種狀況:

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

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

class Foo: def __init__(self, name, age): self.name = name self.age = age obj1 = Foo('張巖林', 18) print(obj1.name)    # 直接調用obj1對象的name屬性
print(obj1.age)     # 直接調用obj1對象的age屬性
 obj2 = Foo('Aylin', 18) print(obj2.name)    # 直接調用obj2對象的name屬性
print(obj2.age )    # 直接調用obj2對象的age屬性

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

class Foo: def __init__(self,backend): '''構造方法''' self.backend = backend  #普通字段
        self.auther = "張巖林"

    def feach(self): print(self.backend,"做者:",self.auther) def add(self): print(self.backend,"做者:",self.auther) #建立對象並把www.baidu.com封裝到對象中
obj = Foo("www.baidu.com") obj.feach() obj1 = Foo("www.google.com") obj1.add()

demo 2、繼承繼承,面向對象中的繼承和現實生活中的繼承相同,即:子能夠繼承父的內容。例如:  貓能夠:喵喵叫、吃、喝、拉、撒  狗能夠:汪汪叫、吃、喝、拉、撒吃、喝、拉、撒是貓和狗都具備的功能,而咱們卻分別的貓和狗的類中編寫了兩次。若是使用 繼承 的思想,以下實現:  動物:吃、喝、拉、撒     貓:喵喵叫(貓繼承動物的功能)     狗:汪汪叫(狗繼承動物的功能)

#繼承實例
class Animals: def chi(self): print(self.name+"") def he(self): print(self.name+"") def la(self): print(self.name+"") def jiao(self): print("叫叫") class Uncle: def jiao(self): print("叫叫叫") class dog(Animals,Uncle): def __init__(self,name): self.name = name def jiao(self): print("") ddog = dog("") ddog.chi() ddog.jiao()

demo因此,對於面向對象的繼承來講,其實就是將多個類共有的方法提取到父類中,子類僅需繼承父類而沒必要一一實現每一個方法。注:除了子類和父類的稱謂,你可能看到過 派生類 和 基類 ,他們與子類和父類只是叫法不一樣而已。 那麼問題又來了,多繼承呢?

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

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

class Zhang(object): def f1(self): print("zhang") class A(Zhang): def f(self): print("A") class B(A): def f(self): print("B") class C(Zhang): def f1(self): print("C") class D(C): def f(self): print("D") class E(D,B): def f(self): print("E") ret = E() ret.f1()

demo 3、多態  Pyhon不支持多態而且也用不到多態,多態的概念是應用於Java和C#這一類強類型語言中,而Python崇尚「鴨子類型」。

class F1: pass


class S1(F1): def show(self): print ('S1.show') class S2(F1): def show(self): print( 'S2.show') # 因爲在Java或C#中定義函數參數時,必須指定參數的類型 # 爲了讓Func函數既能夠執行S1對象的show方法,又能夠執行S2對象的show方法,因此,定義了一個S1和S2類的父類 # 而實際傳入的參數是:S1對象和S2對象

def Func(F1 obj): """Func函數須要接收一個F1類型或者F1子類的類型"""
    
    print (obj.show()) s1_obj = S1() Func(s1_obj) # 在Func函數中傳入S1類的對象 s1_obj,執行 S1 的show方法,結果:S1.show
 s2_obj = S2() Func(s2_obj) # 在Func函數中傳入Ss類的對象 ss_obj,執行 Ss 的show方法,結果:S2.show

python僞代碼實現java,c#多態

class F1: pass


class S1(F1): def show(self): print ('S1.show') class S2(F1): def show(self): print( 'S2.show') def Func(obj): print( obj.show()) s1_obj = S1() Func(s1_obj) s2_obj = S2() Func(s2_obj) 

python「鴨子類型」 類成員  一、字段:
靜態字段:提供給類裏每一個對象(方法)使用
普通字段:讓每一個方法都有不一樣的數據

二、方法:
靜態方法: 無需使用對象封裝,用類方法執行
類方法: 類方法執行,調用時會顯示出當前是哪一個類
普通方法: 對象方式執行,使用對象中的數據

三、特性:
能夠獲取特性 也能夠設置特性

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

  • 普通字段屬於對象
  • 靜態字段屬於

class Province:

    # 靜態字段
    country = '中國'

    def __init__(self, name):

        # 普通字段
        self.name = name


# 直接訪問普通字段
obj = Province('河北省')
print(obj.name)

# 直接訪問靜態字段
Province.country

View Code由上述代碼能夠看出【普通字段須要經過對象來訪問】【靜態字段經過類訪問】,在使用上能夠看出普通字段和靜態字段的歸屬是不一樣的。其在內容的存儲方式相似以下圖:注:靜態字段只在內存中保存一份,普通字段在每一個對象中都要保存一份 2、方法方法包括:普通方法、靜態方法和類方法,三種方法在內存中都歸屬於類,區別在於調用方式不一樣。  一、普通方法:由對象調用;至少一個self參數;執行普通方法時,自動將調用該方法的對象賦值給self  二、類方法:由調用; 至少一個cls參數;執行類方法時,自動將調用該方法的複製給cls  三、靜態方法:由調用;無默認參數;

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()

定義方法並使用相同點:對於全部的方法而言,均屬於類(非對象)中,因此,在內存中也只保存一份。不一樣點:方法調用者不一樣、調用方法時自動傳入的參數不一樣。 3、特性  若是你已經瞭解Python類中的方法,那麼特性就很是簡單了,由於Python中的屬性實際上是普通方法的變種。對於特性,有如下兩個知識點:  一、特性的基本使用  二、特性的兩種定義方式 一、特性的基本使用

# ############### 定義 ###############
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 二、屬性的兩種定義方式屬性的定義有兩種方式:  一、裝飾器 即:在方法上應用裝飾器  二、靜態字段 即:在類中定義值爲property對象的靜態字段 1.1 裝飾器方式經典類,具備一種@property裝飾器

# ############### 定義 ###############    
class Goods:

    @property
    def price(self):
        return "張巖林"
# ############### 調用 ###############
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 1.2 靜態字段方式,建立值爲property對象的靜態字段當使用靜態字段的方式建立屬性時,經典類和新式類無區別

class Foo:

    def get_bar(self):
        return '張巖林'

    BAR = property(get_bar)

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

View Codeproperty的構造方法中有個四個參數  一、第一個參數是方法名,調用 對象.屬性 時自動觸發執行方法  二、第二個參數是方法名,調用 對象.屬性 = XXX 時自動觸發執行方法  三、第三個參數是方法名,調用 del 對象.屬性 時自動觸發執行方法  四、第四個參數是字符串,調用 對象.屬性.__doc__ ,此參數是該屬性的描述信息

class Foo:

    def get_bar(self):
        return 'zhangyanlin'

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

    def del_bar(self):
        return "張巖林"

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

obj = Foo()

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

View Code因爲靜態字段方式建立屬性具備三種訪問方式,咱們能夠根據他們幾個屬性的訪問特色,分別將三個方法定義爲對同一個屬性:獲取、修改、刪除

class Goods(object):

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

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

    def set_price(self, value):
        self.original_price = value

    def del_price(self, value):
        del self.original_price

    PRICE = property(get_price, set_price, del_price, '價格屬性描述...')

obj = Goods()
obj.PRICE         # 獲取商品價格
obj.PRICE = 200   # 修改商品原價
del obj.PRICE     # 刪除商品原價

View Code因此,定義屬性共有兩種方式,分別是【裝飾器】和【靜態字段】,而【裝飾器】方式針對經典類和新式類又有所不一樣。 類成員修飾符 類的全部成員在上一步驟中已經作了詳細的介紹,對於每個類的成員而言都有兩種形式:  一、公有成員,在任何地方都能訪問  二、私有成員,只有在類的內部才能方法 私有成員和公有成員的定義不一樣:私有成員命名時,前兩個字符是下劃線。(特殊成員除外,例如:__init__、__call__、__dict__等) 

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

私有成員和公有成員的訪問限制不一樣 一、靜態字段  一、公有靜態字段:類能夠訪問;類內部能夠訪問;派生類中能夠訪問  二、私有靜態字段:僅類內部能夠訪問;

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() # 派生類中能夠訪問   ==> 錯誤

私有字段二、普通字段  一、公有普通字段:對象能夠訪問;類內部能夠訪問;派生類中能夠訪問  二、私有普通字段:僅類內部能夠訪問;注:若是想要強制訪問私有字段,能夠經過 【對象._類名__私有字段明 】訪問(如:obj._C__foo),不建議強制訪問私有成員。 

class C:
    
    def __init__(self):
        self.foo = "公有字段"

    def func(self):
        print(self.foo)  # 類內部訪問

class D(C):
    
    def show(self):
        print(self.foo) # 派生類中訪問

obj = C()

obj.foo     # 經過對象訪問
obj.func()  # 類內部訪問

obj_son = D();
obj_son.show()  # 派生類中訪問

公有字段

class C:
    
    def __init__(self):
        self.__foo = "私有字段"

    def func(self):
        print(self.foo ) # 類內部訪問

class D(C):
    
    def show(self):
        print(self.foo) # 派生類中訪問

obj = C()

obj.__foo     # 經過對象訪問    ==> 錯誤
obj.func()  # 類內部訪問        ==> 正確

obj_son = D();
obj_son.show()  # 派生類中訪問  ==> 錯誤

私有字段 類的特殊成員 一、 __doc__  表示類的描述信息

class Foo:
    """ 描述類信息,這是用於看片的神奇 """

    def func(self):
        pass

print Foo.__doc__
#輸出:類的描述信息

View Code二、 __module__ 和  __class__   __module__ 表示當前操做的對象在那個模塊  __class__     表示當前操做的對象的類是什麼

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

class C:

    def __init__(self):
        self.name = 'zhangyanlin'

lib/test.py

from lib.test import C

obj = C()
print obj.__module__  # 輸出 lib.aa,即:輸出模塊
print obj.__class__      # 輸出 lib.aa.C,即:輸出類

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

class Foo:

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


obj = Foo('張巖林') # 自動執行類中的 __init__ 方法

View Code

class Annimal:
    def __init__(self):
        print("動物構造方法")
        self.name = "動物"

class Dog(Annimal):
    def __init__(self):
        print("狗狗構造方法")
        self.nn = ""
        super(Dog,self).__init__()
        # Annimal.__init__(self)



d = Dog()
print(d.__dict__)

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

class Foo:

    def __del__(self):
        pass

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

class Foo:

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

        print (__call__)


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

View Code六、 __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'}

obj2 = Province('HeNan', 3888)
print obj2.__dict__
# 獲取 對象obj1 的成員
# 輸出:{'count': 3888, 'name': 'HeNan'}

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

class Foo:

    def __str__(self):
        return 'zhangyanlin'


obj = Foo()
print(obj)
# 輸出:zhangyanlin

View Code八、__getitem__、__setitem__、__delitem__用於索引操做,如字典。以上分別表示獲取、設置、刪除數據

class Foo:

    def __getitem__(self, item):  # 獲取
        print(item)

    def __setitem__(self, key, value): # 設置
        print(key,value)

    def __delitem__(self, key): # 刪除
        print(key)

obj = Foo()

obj["張巖林"]     # 調用getitem
obj["name"]=1234   # 調用setitem
del obj["namename"] # 調用delitem
print(Foo.__dict__)

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

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

class Foo(object):

    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

View Code

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

obj = iter([11,22,33,44])

while True:
    val = obj.next()
    print(val)

for循環內部語法 單例模式 所謂單例,是指一個類的實例從始至終只能被建立一次。 方法1若是想使得某個類從始至終最多隻有一個實例,使用__new__方法會很簡單。Python中類是經過__new__來建立實例的:

class Singleton(object):
    def __new__(cls,*args,**kwargs):
        if not hasattr(cls,'_inst'):
            cls._inst=super(Singleton,cls).__new__(cls,*args,**kwargs)
        return cls._inst
if __name__=='__main__':
    class A(Singleton):
        def __init__(self,s):
            self.s=s     
    a=A('apple')  
    b=A('banana')
    print(id(a),a.s)
    print(id(b),b.s)

結果:

29922256 banana
29922256 banana

經過__new__方法,將類的實例在建立的時候綁定到類屬性_inst上。若是cls._inst爲None,說明類還未實例化,實例化並將實例綁定到cls._inst,之後每次實例化的時候都返回第一次實例化建立的實例。注意從Singleton派生子類的時候,不要重載__new__。 方法2當你編寫一個類的時候,某種機制會使用類名字,基類元組,類字典來建立一個類對象。新型類中這種機制默認爲type,並且這種機制是可編程的,稱爲元類__metaclass__ 。

class Singleton(type):
    def __init__(self,name,bases,class_dict):
        super(Singleton,self).__init__(name,bases,class_dict)
        self._instance=None
    def __call__(self,*args,**kwargs):
        if self._instance is None:
            self._instance=super(Singleton,self).__call__(*args,**kwargs)
        return self._instance
if __name__=='__main__':
    class A(object):
        __metaclass__=Singleton      
    a=A()
    b=A()
    print(id(a),id(b))

結果:

34248016 34248016

id是相同的。例子中咱們構造了一個Singleton元類,並使用__call__方法使其可以模擬函數的行爲。構造類A時,將其元類設爲Singleton,那麼建立類對象A時,行爲發生以下:A=Singleton(name,bases,class_dict),A其實爲Singleton類的一個實例。建立A的實例時,A()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).__call__(),這樣就將A的全部實例都指向了A的屬性_instance上,這種方法與方法1實際上是相同的。 方法4最簡單的方法:

class singleton(object):
    pass
singleton=singleton()

將名字singleton綁定到實例上,singleton就是它本身類的惟一對象了。 方法5

class ConnectionPool:

    __instance = None
    def __init__(self):
        self.ip = "192.168.1.1"
        self.port = 3306
        self.username = "zhangyanlin"
        self.pwd = 123456

    @staticmethod
    def get_instance():
        if ConnectionPool.__instance:
            return ConnectionPool.__instance
        else:
            ConnectionPool.__instance = ConnectionPool()
            return ConnectionPool.__instance

obj1 = ConnectionPool()
print(obj1.get_instance())

obj2 = ConnectionPool()
print(obj2.get_instance())

obj3 = ConnectionPool()
print(obj3.get_instance())

定義靜態方法,判斷讓全部只用第一個對象在內存中建立的ID        

相關文章
相關標籤/搜索