用Python的func和dict模擬js或lua的面向物件
今天又重新看了一下js,也看了之前沒學的js的面向物件(之前的課缺的太多,這次花了半個小時百度了一點相關知識),突然感覺,js和lua的面向物件挺像的(lua沒有物件的概念,只是用table模擬的物件,我說感覺js和lua在這點很像,可能會有很多jsor(自己編的詞)會揍我(畢竟我js沒看全,可能理解有誤)),所以我就嘗試python的dict模擬了一下js或lua的面向物件,可能是我受lua的影響,總覺的js的面向物件就是模擬的,不說了,看程式碼:
首先:說一下我的python方面的理解(個人見解,C語言不咋會,所以可能理解有誤): 對於python,所有的變數都是C指標變數,函式也是,這也說明了我們無論存什麼資料,其實存的都是指標,可以對比一下Python和C: 先看下Python:
def func(a, b): return a if a>b else b
f = func # ----------------------------------注意對比01
c = f(1, 2) # ----------------------------------注意對比02
print(c) # ==>輸出 2
再看C:
void main() { int max(int, int); int (*p)(); int c; p = max; # ----------------------------------注意對比01 c = (*p)(1, 2); # ----------------------------------注意對比02 printf("a = %d, b = %d, max = %d\n", a, b, c); } int max(int a, int b) { return a > b ? a : b;}
其實我們從下邊也能看出來:
def func(a, b): return a if a>b else b
print(func) # 輸出<function func at 0x00000000005FC378>此為函式地址
所以在Python中可以將函式放進字典裡邊,同時也能呼叫函式:
def func1(): pass
dic = {"func1": func1}
dic['func']()
PS:其實從這也能看出,閉包也沒什麼了,原理類似。 那麼,我們來用dict模擬一下物件的抽象和封裝:
def func1(): return 1 def func2(): return 2 def func3(): return 3 # 下邊為物件(類?)的屬性新增 dic["a"] = 1 dic["b"] = 2 # print(eval("func1()")) # 此為下邊字典生成器的原理 dic = {("func" + str(i)):eval("func" + str(i)) for i in range(1, 4)} # 物件的方法新增
正面我們來輸出一下物件dict的屬性和方法:
print("a", ": ", dic["a"]) # 屬性
print("b", ": ", dic["a"]) # 屬性
print("dic.func1()", ": ", dic["func1"]()) # 方法
print("dic.func2()", ": ", dic["func2"]()) # 方法
print("dic.func3()", ": ", dic["func3"]()) # 方法
輸出結果分別是:
a : 1
b : 1
dic.func1() : 1
dic.func2() : 2
dic.func3() : 3
也許你會說,物件還有繼承和重寫呢? 那我們來看看下邊的: 首先定義一個function,用來模擬類:
def Classfunc(a, b, c):
dic["a"] = a
dic["b"] = b
dic["c"] = c
def func01(): return 11
def func02(): return 22
def func03(): return 33
dic["func01"] = func01
dic["func02"] = func02
dic["func03"] = func03
return dic # 返回一個字典,這樣就能通過函式的返回值模擬建立物件了
類建立好了,現在我們來“建立物件”:cf,並輸出cf的“屬性”和“方法”
cf = Classfunc("aa", "bb", "cc")
print("a", ": ", cf["a"]) # 屬性
print("b", ": ", cf["b"]) # 屬性
print("c", ": ", cf["c"]) # 屬性
print("cf.func3()", ": ", cf["func01"]()) # 方法
print("cf.func3()", ": ", cf["func02"]()) # 方法
print("cf.func3()", ": ", cf["func03"]()) # 方法
當然,我們也可以得到:
a : aa
b : bb
c : cc
cf.func3() : 11
cf.func3() : 22
cf.func3() : 33
那繼承和重寫呢?繼續看: 上邊咱們寫了父類ClassFunc了,下邊咱們來模擬子類繼承父類:
def Classfunc(d, e, sc={}): #sc-->SuperClass父類
dic = {k: v for k, v in sc.items()} # 通過對sc的copy實現繼承
dic["d"] = d # 子類新增屬性
dic["e"] = e
dic["a"] = "aa_重寫" if sc else "aa" # 實現重寫 或 增加屬性
def refunc01(): return "重寫func01"
def func01(): return "增加方法func01"
dic["func01"] = refunc01 if sc else func01 # 實現重寫 或 增加方法
def func04(): return 44 # "增加方法func04"
dic["func04"] = func04
return dic
下面我們來分別模擬有繼承和無繼承的情況: 無繼承:
cf1 = Classfunc("dd", "ee") # 無繼承
print("a", ": ", cf1["a"]) # 屬性 重寫了(此時的重寫其實是增加屬性)
try:
print("b", ": ", cf1["b"]) # 屬性b未繼承
except Exception as e:
print("屬性b不存在")
try:
print("c", ": ", cf1["c"]) # 屬性c未繼承
except Exception as e:
print("屬性c不存在")
print("d", ": ", cf1["d"]) # 屬性
print("e", ": ", cf1["e"]) # 屬性
print("cf1.func1()", ": ", cf1["func01"]()) # 方法1 重寫的
# 由於try之後出現
# During handling of the above exception, another exception occurred:
# 不知道咋回事,就不try了(python沒學好)
# print("cf1.func2()", ": ", cf1["func02"]()) # 方法2未繼承
# print("cf1.func3()", ": ", cf1["func03"]()) # 方法3未繼承
print("cf1.func4()", ": ", cf1["func04"]()) # 方法4 新增的
這時,輸出結果是:
a : aa
屬性b不存在
屬性c不存在
d : dd
e : ee
cf1.func1() : 增加方法11
cf1.func4() : 44
同樣,對於有繼承的:
cf2 = Classfunc("d", "e", sc=cf) # 有繼承
print("a", ": ", cf2["a"]) # 屬性 重寫了(此時的重寫其實是增加屬性)
print("b", ": ", cf2["b"]) # 屬性b有繼承
print("c", ": ", cf2["c"]) # 屬性c有繼承
print("d", ": ", cf2["d"]) # 屬性
print("e", ": ", cf2["e"]) # 屬性
print("cf2.func1()", ": ", cf2["func01"]()) # 方法1 重寫
print("cf2.func2()", ": ", cf2["func02"]()) # 方法2未繼承
print("cf2.func3()", ": ", cf2["func03"]()) # 方法3未繼承
print("cf2.func4()", ": ", cf2["func04"]()) # 方法
輸出為:
a : aa_重寫
b : bb
c : cc
d : d
e : e
cf2.func1() : 重寫func 11
cf2.func2() : 22
cf2.func3() : 33
cf2.func4() : 44
其實,通過python對字典的處理(有key時為修改,無key時為新增,和物件類似,js和lua中也是這樣),我們就可以用字典(lua中叫table)(模擬類)和函式(模擬類屬性和類方法的實現)來模擬出面向物件了。
也許你又雙叕會問了,面向物件還有多型呢?方法的重寫不就是?其他的幾種就別問我了,自己思考吧,我懶得思考了。
剛剛想起來,上邊的繼承是單繼承,如果是多繼承,這樣就好了:
def Classfunc(d, e, *arg_sc): #sc-->SuperClass
dic = {}
for d in arg_sc: # 先遍歷所有父類
for k, v in d.items():
if not dic.has_key(k):
dic[k] = v
# 如果為了速度,用字典生成器則是:
# dic = {k: v for d in arg_sc for k, v in d.items() if not dic.has_key(k)}
在想剛剛這個問題的時候,我對父類有相同方法名的繼承問題有疑惑,因此手動測試了一下:
class A(object):
def a(self):
return "a1"
def b1(self):
return "b1"
class B(object):
def a(self):
return "a2"
def b2(self):
return "b2"
class C(A, B):
def c(self):
return "C"
a = A()
b = B()
c = C()
print(a.a()) # ==>輸出 a1
print(a.b1()) # ==>輸出 b1
print(b.a()) # ==>輸出 a2
print(b.b2()) # ==>輸出 b2
print()
print(c.a()) # 繼承第一個 # ==>輸出 a1
print(c.b1()) # ==>輸出 b1
print(c.b2()) # ==>輸出 b2
print(c.c()) # ==輸出 >C
# 通過以上發現,如果子類繼承的父類中有相同方法名的方法,則繼承第一個繼承的
最後,如果大佬們覺得我的理解有錯誤,請不吝賜教!謝謝!!!