美文网首页
一次错综离奇的super调用的None参数super() arg

一次错综离奇的super调用的None参数super() arg

作者: 马小李23 | 来源:发表于2022-08-25 16:13 被阅读0次

最近在python的代码中,使用装饰器的功能以后,遇到了一个有意思的错误,记录下与大家分享一下,希望大家不会犯同样的错误。

大致代码如下:

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

运行的时候,在创建TestClass的对象的时候,报错如下:

in init

super() argument 1 must be type, not None

检查代码的时候,先查看了fn_list[‘TestClass’]确实指向了对应的类,不是None。

init函数中,输出self,发现是对应类的对象,然后输出TestClass,发现是None。

但是调用同样用装饰器装饰的print_test没有发生问题。

其实问题就出在装饰器函数上,装饰器的作用其实就是在对象(例如函数,类)定义的时候 改变这个对象后续调用过程中的行为,又不改变这个对象内部代码。

以装饰某一个函数为例子,比如装饰器是decrator函数,装饰在print_test函数,那么在函数print_test定义的时候(此时函数print_test不被调用),首先调用了一次print_test = decorator(print_test),对于print_test的函数进行定义。那么,此时指向print_test对象的指针,已经被替换成了指向decorator(print_test)的指针。这里需要注意的是,此时print_test函数已经被覆盖成了新的函数decorator(print_test),即调用decorator函数,并将print_test作为参数传入,得到的返回值,即print_test = decorator(print_test)。

详细的了解了装饰器的工作机制,就不难理解上述问题的出现了。

首先,为什么调用print_test会有正确的结果,这个是因为在装饰器中,保存了print_test的调用入口,并且是通过这个入口调用的(ouput_result = fn_list'print_test')。但是,如果直接调用print_test('1234'),会出错。

其次,创建对象为什么会报错。这个是因为,创建对象调用,从保留的正确入口进行了调用(fn_list'TestClass'),但是,在类初始化的init函数中,调用super的时候,是用的函数名称TestClass进行直接调用的,这个时候,其实TestClass已经在定义的时候,因为调用TestClass = decorator(TestClass) 而变成了None(decorator没有显式指定返回值,所以为默认返回值None),这样就产生了最终的这个错综离奇的报错。

太长不看系列:

装饰器原理,对于用装饰器修饰的函数定义:

@decorator
def func():
    pass

在定义时,先调用了func = decorator(func),对于func进行了定义的修改。

由于decorator在我的代码中没有显式定义返回值,则使用的默认返回值None。

于是所有被装饰的函数和类,都被设置为None的变量。

修改办法

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

相关文章

  • 一次错综离奇的super调用的None参数super() arg

    最近在python的代码中,使用装饰器的功能以后,遇到了一个有意思的错误,记录下与大家分享一下,希望大家不会犯同样...

  • 底层13:Runtime-Super

    super: super调用,底层会转换为objc_msgSendSuper2的函数的调用,接收2个参数:stru...

  • Runtime:super的本质

    super的本质 super调用,底层会转换为objc_msgSendSuper2函数的调用,接收2个参数stru...

  • iOS 之self和super区别

    要点: self 调用自己方法,super 调用父类方法 self是类隐藏参数,super是预编译指令 【self...

  • 8、继承抽象类接口--看书ing

    1.0 调用父类的特殊构造方法在第一行用super(对应参数);如果不写super();则会自动调用无参构造方法,...

  • self和super小结

    关键区分: 1.self是类隐藏参数,super是预编译指令2.self 调用本类方法,super 调用父类方法3...

  • Python子类中调用父类的classmethod方法

    在子类中调用父类的classmethod方法,可以使用super() 输入结果: super()函数的第一个参数是...

  • JavaScript零散知识点

    继承 super 在子类中调用super,会调用父类的方法; 不用super,则会覆盖父类的方法。调用本类中的方法。

  • ES6 类\继承\接口

    super方法 子类必须在constructor方法中调用super方法调用super方法必须放到this初始化实...

  • self和super的区别

    self和super的区别 self调用自己方法,super调用父类方法 self是类,super是预编译指令 [...

网友评论

      本文标题:一次错综离奇的super调用的None参数super() arg

      本文链接:https://www.haomeiwen.com/subject/ohqzgrtx.html