1. 程式人生 > >用Python的func和dict模擬js或lua的面向物件

用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

# 通過以上發現,如果子類繼承的父類中有相同方法名的方法,則繼承第一個繼承的

最後,如果大佬們覺得我的理解有錯誤,請不吝賜教!謝謝!!!