1报错情景描述

笔者在写完一个普通类之后,没有实例化,直接调用类的方法,出现以下错误:
在这里插入图片描述

我们这里先看源代码:

class A:
    def __init__(self, id):
        self.id = id
    
    def fun1():
        print('fun1')

if __name__ == "__main__":  
    
    A.fun1()

2报错分析

从报错代码能够看出,A类的 fun1() 就是这个类下的一个方法。我没有实例化,直接调用A类类方法fun1(),所以就报错了。

有点经验的人会说,你都没实例化,肯定会报错,当然不对了,我们暂且就把这个这个作为云因吧。

3解决方法

方法一:
既然我没有实例化,那么我就先实例化,然后在调用方法。

class A:
    def __init__(self, id):
        self.id = id
    
    def fun1(self):
        print('fun1')

if __name__ == "__main__":  
    
    a = A(1)
    a.fun1()

这个没有人有异议吧,肯定没有问题。

方法二:
我们回到错误的提示,错误提示fun1()方法没有’self’,而’self’代表类本身,我们有没实例化,也就找不到’self’,那么我们不传’self’可以不,我们试试。

class A:
    def __init__(self, id):
        self.id = id
    
    def fun1():
        print('fun1')

if __name__ == "__main__":  
    A.fun1()

结果如下:
在这里插入图片描述

好像可以啊,没有问题。这样其实是不规范的,Python代码比较随意,当你没有实例化,又,这种调用方法,其类方法就退化成一个普通的函数,普通函数没有’self’参数。

方法三:
重点来了,一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。而使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。那么它们之间有啥区别呢?我们先看代码,再来分析。

class A:
    def __init__(self, id):
        self.id = id
    
    def fun1(self):
        print('fun1', self)
        
    @staticmethod
    def fun2(self):
        print('fun2', self)

    @classmethod
    def fun3(self):
        print('fun3', self)
        
if __name__ == "__main__":  

    t1 = time.time()
    
    a = A(1)
    a.fun1()

    A.fun1(a)
    
    A.fun2(a)
    
    A.fun3()

结果如下所示:

在这里插入图片描述

看到上面的结果,估计有人又有疑惑了,都是打印’self’,怎么第四个不一样呢?我们一一分析。

a.fun1() 就不应说了,就是不同的调用,打印’self’就是打印实例a的地址。

A.fun1(a) 就需要注意了,我们在前文说不是不能有’self’吗,怎么又传了参数,注意了,我们这里只是传了一个类对象而已,也传了参数的,也相当于调用的普通函数。’self’在该方法中就相当于一个普通参数而已。

A.fun2(a) 就是所谓的静态方法。这里要注意的是,在Python 2 中,如果一个类的方法不需要self参数,必须声明为静态方法,即加上@staticmethod装饰器,从而不带实例调用它。而在Python 3中,如果一个类的方法不需要self参数,不再需要声明为静态方法,但是这样的话只能通过类去调用这个方法,如果使用实例调用这个方法会引发异常,因此,在Python3中,加上@staticmethod装饰器和fun1方法是一样的。

A.fun3() 表示一个类方法,不需要实例化,方法中’self’表示可以来调用类的属性,类的方法,实例化对象等,一般用’cls’表示,因此打印的结果是一个类,而不是实例化的类对象的地址。

总结:
1.在Python类中最好不要写静态方法,因为如果实例化一个类后,调用没有self参数的方法,会隐式地将self参数传入方法,而方法本身不接受任何参数,从而引发异常。

2.使用装饰符 @classmethod的好处就是重构类的时候不必要修改构造函数,只需要额外添加你要处理的函数,而且不需要实例化,直接类名.方法名来调用

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐