一次錯綜離奇的super調(diào)用的None參數(shù)super() argument 1 must be type, not None

最近在python的代碼中,使用裝飾器的功能以后,遇到了一個(gè)有意思的錯誤,記錄下與大家分享一下,希望大家不會犯同樣的錯誤。

大致代碼如下:

fn_list = {}


def decrator(fn):
    fn_list[fn.__name__] = fn


@decrator
def print_test(index):
    print(index)
    return 'success'


@decrator
class TestClass(object):

    def __init__(self):
        super(TestClass, self).__init__()
        print("finish init func")


ouput_result = fn_list['print_test']('1234')
print(ouput_result)
test_instance = fn_list['TestClass']()

運(yùn)行的時(shí)候,在創(chuàng)建TestClass的對象的時(shí)候,報(bào)錯如下:

in init

super() argument 1 must be type, not None

檢查代碼的時(shí)候,先查看了fn_list[‘TestClass’]確實(shí)指向了對應(yīng)的類,不是None。

init函數(shù)中,輸出self,發(fā)現(xiàn)是對應(yīng)類的對象,然后輸出TestClass,發(fā)現(xiàn)是None。

但是調(diào)用同樣用裝飾器裝飾的print_test沒有發(fā)生問題。

其實(shí)問題就出在裝飾器函數(shù)上,裝飾器的作用其實(shí)就是在對象(例如函數(shù),類)定義的時(shí)候 改變這個(gè)對象后續(xù)調(diào)用過程中的行為,又不改變這個(gè)對象內(nèi)部代碼。

以裝飾某一個(gè)函數(shù)為例子,比如裝飾器是decrator函數(shù),裝飾在print_test函數(shù),那么在函數(shù)print_test定義的時(shí)候(此時(shí)函數(shù)print_test不被調(diào)用),首先調(diào)用了一次print_test = decorator(print_test),對于print_test的函數(shù)進(jìn)行定義。那么,此時(shí)指向print_test對象的指針,已經(jīng)被替換成了指向decorator(print_test)的指針。這里需要注意的是,此時(shí)print_test函數(shù)已經(jīng)被覆蓋成了新的函數(shù)decorator(print_test),即調(diào)用decorator函數(shù),并將print_test作為參數(shù)傳入,得到的返回值,即print_test = decorator(print_test)。

詳細(xì)的了解了裝飾器的工作機(jī)制,就不難理解上述問題的出現(xiàn)了。

首先,為什么調(diào)用print_test會有正確的結(jié)果,這個(gè)是因?yàn)樵谘b飾器中,保存了print_test的調(diào)用入口,并且是通過這個(gè)入口調(diào)用的(ouput_result = fn_list'print_test')。但是,如果直接調(diào)用print_test('1234'),會出錯。

其次,創(chuàng)建對象為什么會報(bào)錯。這個(gè)是因?yàn)?,?chuàng)建對象調(diào)用,從保留的正確入口進(jìn)行了調(diào)用(fn_list'TestClass'),但是,在類初始化的init函數(shù)中,調(diào)用super的時(shí)候,是用的函數(shù)名稱TestClass進(jìn)行直接調(diào)用的,這個(gè)時(shí)候,其實(shí)TestClass已經(jīng)在定義的時(shí)候,因?yàn)檎{(diào)用TestClass = decorator(TestClass) 而變成了None(decorator沒有顯式指定返回值,所以為默認(rèn)返回值None),這樣就產(chǎn)生了最終的這個(gè)錯綜離奇的報(bào)錯。

太長不看系列:

裝飾器原理,對于用裝飾器修飾的函數(shù)定義:

@decorator
def func():
    pass

在定義時(shí),先調(diào)用了func = decorator(func),對于func進(jìn)行了定義的修改。

由于decorator在我的代碼中沒有顯式定義返回值,則使用的默認(rèn)返回值None。

于是所有被裝飾的函數(shù)和類,都被設(shè)置為None的變量。

修改辦法

def decrator(fn):
    fn_list[fn.__name__] = fn
    return fn
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 包(lib)、模塊(module) 在Python中,存在包和模塊兩個(gè)常見概念。 模塊:編寫Python代碼的py...
    清清子衿木子水心閱讀 3,907評論 0 27
  • 1.1==,is的使用 ·is是比較兩個(gè)引用是否指向了同一個(gè)對象(引用比較)。 ·==是比較兩個(gè)對象是否相等。 1...
    TENG書閱讀 788評論 0 0
  • 初次接觸測試框架的你,肯定希望能更快速的編寫自己的測試代碼,那么我們開始吧! 1.Pytest介紹 pytest是...
    白習(xí)習(xí)_c942閱讀 7,391評論 0 15
  • 1.元類 1.1.1類也是對象 在大多數(shù)編程語言中,類就是一組用來描述如何生成一個(gè)對象的代碼段。在Python中這...
    TENG書閱讀 1,418評論 0 3
  • sorted()也是一個(gè)高階函數(shù)。用sorted()排序的關(guān)鍵在于實(shí)現(xiàn)一個(gè)映射函數(shù)。 函數(shù)作為返回值 高階函數(shù)除了...
    jbb_43b0閱讀 393評論 0 0

友情鏈接更多精彩內(nèi)容