本篇內容: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)
二、hasattr
經過字符串的形式去某個模塊中判斷東西是否存在
import commas #去commas模塊中尋找f1,有返回true,沒有返回none
target_func = hasattr(commas,"f1") print(target_func)
三、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)
四、delattr
import commas target_func = hasattr(commas,"f1") print(target_func) del_func = delattr(commas,"f1") target_func = hasattr(commas,"f1") print(target_func)
案例:程序員
''' 基於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 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
第二步:從某處調用被封裝的內容調用被封裝的內容時,有兩種狀況:
一、經過對象直接調用被封裝的內容上圖展現了對象 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