当前位置: 首页 > 科技观察

基于这3点,你就可以全面理解Python的类方法和静态方法了

时间:2023-03-18 15:42:35 科技观察

Python语言中有以下3种方法:成员方法类方法(classmethod)静态方法(staticmethod)很多同学可能不知道这3种方法,尤其是后两种方法有什么区别。为此,本文将对这三种方法进行深入分析。先说一下这三种方法的区别。了解了区别之后,自然就会明白它们之间的区别。这3个方法有以下3个区别:方法定义调用方法方法属性1.方法定义这3个方法在定义上有以下2个区别。(1)是否使用装饰器成员方法不需要使用任何装饰器,直接使用def关键字定义方法即可,代码如下:defmethod(self,a,b,c):passclassmethodmust用@classmethod装饰器装饰,代码如下:@classmethoddefmethod(cls,a,b,c):pass静态方法必须用@staticmethod装饰器装饰,代码如下:@staticmethoddefmethod(a,b,c):pass(2)成员方法和类的参数不同除了正常的方法参数外,方法还必须增加一个额外的参数,这个参数必须是方法的第一个参数。参数可以是任意名称,但通常成员方法的第一个参数名称是self,类方法的第一个参数名称是cls。静态方法不需要额外的参数。请参阅前面代码中的方法方法。self和cls分别代表类实例和类本身,后面会详细介绍。我们来看一段完整定义这三个方法的代码:classMyClass(object):#Membermethoddeffoo(self,x):print("executingfoo(%s,%s)"%(self,x))#Classmethod@classmethoddefclass_foo(cls,x):print("executingclass_foo(%s,%s)"%(cls,x))#staticmethod@staticmethoddefstatic_foo(x):print("executingstatic_foo(%s)"%x)2.调用方法(一)调用成员方法成员方法只能通过类实例调用,代码如下:my=MyClass()my.foo(20)定义成员方法时,第一个参数self代表类实例,而这个参数不需要在调用时显式指定,而是由Python运行时自动处理。对于上面的调用代码,Python运行时会自动将代表MyClass实例的my传递给foo方法。所以my就是foo方法中第一个参数self的值。通过self,可以在方法内部引用MyClass实例的其他成员。执行此代码将输出以下内容。很明显,self是一个对象,首地址是0x7f7f1003df70executingfoo(<__main__.MyClassobjectat0x7f7f1003df70>,20)(2)调用类方法类方法可以通过类实例调用,也可以直接通过类本身调用。代码如下:my=MyClass()#通过类实例调用my.class_foo(20)#通过类本身调用MyClass.class_foo(20)执行这段代码会输出如下:executingclass_foo(,20)executingclass_foo(,20)很明显,class_foo方法的cls参数不再是类的实例(因为没有对象地址),而是MyClass类本身。所以不管用哪个方法调用类方法,传递给class_foo方法第一个参数的值都是类本身。因此,通过类的方法,可以获得类的静态资源,与直接引用MyClass是一样的。(3)调用静态方法调用静态方法和调用类方法是一样的。两者都可以通过类实例或类本身调用。从这一点来说,分不清哪个是类方法,哪个是静态方法。代码如下:my=MyClass()MyClass.static_foo(20)my.static_foo('hello')执行这段代码,输出结果如下:executingstatic_foo(20)executingstatic_foo(hello)由于没有附加参数在定义静态方法时指定,静态方法不绑定到类或类实例上。当然,在静态方法中,仍然可以通过MyClass引用类的静态成员。3.方法归属方法归属是这三种方法的一个重要区别。你可以将这三个方法作为属性输出,看看结果是什么。my=MyClass())#Outputmembermethodprint(my.foo)#Outputclassmethodprint(my.class_foo)#Outputstaticmethodprint(my.static_foo)执行这段代码,输出如下:>>>>从输出我们可以看出成员方法绑定到类实例(方法属于类实例),并且类方法和类本身是绑定的,静态方法是一个独立的对象(因为它有对象的首地址),不属于任何类或实例。从以上三种方法,我们已经可以看出classmethod方法和staticmethod方法的区别。下面总结一下:4.总结(1)共同点classmethod方法和staticmethod方法只有一个共同点,就是在调用的时候,可以使用类实例,也可以直接从类本身。所以从调用上是分不清是类方法还是静态方法的。(2)顾名思义,差分类方法绑定在类上,相当于下面的调用方法:defprocess(cls,x):print(cls,x)MyClass.process=process#MyClassMyClass直接传过去在调用process方法时.process(MyClass,20)只是类方法在调用时自动传入MyClass,和上面的代码显式传入MyClass,但最终效果是完全一样的。静态方法其实就是一只寄居蟹,根本不属于它的宿主。就住在班里。也就是说,直接把静态方法作为一个独立的函数移出类,一行代码都不用修改就可以直接运行。因为静态方法不访问类的任何成员,当然可以访问类的静态成员,但是它也使用了类本身(比如MyClass)。这种访问方法也可用于独立功能。其实Python提供静态方法并不是很有必要,但是Java却很有必要。由于Python支持独立函数形式,因此可以在不使用静态方法的情况下使用独立函数。通常可以全局访问单个函数(从一个模块到另一个模块中的函数)。Java是纯面向对象的语言,不支持独立函数。所以为了达到这种全局调用的效果,Java类提供了一个静态方法,可以在其他类中通过MyClass.process(...)的形式访问MyClass中的process方法。但是Python中的静态方法有一个作用,就是分组。如果模块中有大量的独立函数,而且这些独立函数的功能可能完全不同,会显得杂乱无章,所以通常的做法是将这些独立函数作为Python类的静态方法,把独立的将同类型的函数合并到一个类中,这样整个代码结构会显得更有条理。就像在硬盘上存储文件一样,如果你把所有的文件都放在一个目录下,那么查找文件就会非常困难。所以需要把同类型的文件放到特定的目录下,这样目录结构看起来更清晰。所以静态方法和Python类就相当于文件和目录的关系,主要起到分类的作用。(3)如果使用场景只是描述类的一般动作,而对于类的不同实例,动作的表现可能不同,则使用成员方法,例如move(移动),fly(fly),getAge(比如类的Person实例不同,可能年龄不一样)等。类方法和静态方法大部分时候是可以互换的,但是如果要保持方法独立,就应该使用静态方法,因为静态方法不需要额外的参数来接收类或类实例。本文转载自微信公众号“极客起源”,可通过以下二维码关注。转载本文请联系极客本源公众号。