草帽路飞UU 发表于 2022-11-15 16:06:06

Python类的多种方法你知道多少

在初学Python过程中,会遇到这样的概念,一个类下面会有多个方法,有的叫类方法、有的叫静态方法,还有的叫实例方法。当调用他们的时候,不免会有点蒙圈,那么他们之间的区别是什么呢?


  和类属性一样,类方法可以进行细致地划分为类方法、实例方法和静态方法。

  表象区别就是:

  类方法前用@classmethod修饰

  静态方法前用@staticmethod修饰

  不加任何修饰的就是实例方法(普通方法)

  用法区别

  实例方法

  也是普通方法,实例方法是我们最常用的方法,它定义时最少要包含一个self参数,用于绑定调用此方法的实例对象(所谓绑定,即用实例调用的时候,不需要显式的传入)。

  换句话说,当实例调用方法的时候,会默认将实例本身传入到这个参数self,而当类直接调用时,因为本身类型是一个class,不是实例对象,所以报错。

  如果非要用类直接调用,需要手动传入一个实例作为第一个参数。注意:若随便传入一个字符串的话,也不会报错,但是会造成程序紊乱,因此不推荐这种调用方式。

  用如下这段代码举例说明:

class A(object):

    def instance_method(self, X):

      print(f'instance_method :{X} : {self}')


a = A()

A.instance_method('x')

A.instance_method(a, 'x')

A.instance_method('strs', 'x')

a.instance_method('a')



  代码中 instance_method 为实例方法,而第6行类A调用了此方法,而实例方法默认传入的应该是实例,而不是类,因此将x当做实例传给了默认的self,此时实例方法还缺少一个参数没有传入,导致报


错:TypeError: instance_method() missing 1 required positional argument: 'x'。

  第7行纠正了第6行的做法,传入了实例a,且传入了一个参数x,所以不会报错,self就是A的实例a。

  第8行将字符串代替实际的实例a传入self,虽不会报错,但是对于程序毫无价值,不推荐这样使用,没有意义。

  第9行是最常用的方法,实例a调用了实例方法,默认将实例a传入了self,再将参数x传入了X,完整实现了调用。

  本地方法

  就当做实例方法的一种吧,好奇心的驱使,如果实例方法没有添加self这个参数呢,为了区分,我们且叫他“本地方法”。所谓本地,也就是实例无法调用,只能类自己调用。

class A(object):

    def local_method():

      print(f'local_method')


    def local_method2(strs):

      print(f'local_method2')


a = A()

a.local_method()

a.local_method2()

A.local_method()


  如上代码,第2行的local_method()就是个本地方法,而此时在第9行实例a调用这个本地方法的时候,由于程序会默认将实例a传入参数self,但是本地方法没有写self,因此报错:TypeError:

A.local_method() takes 0 positional arguments but 1 was given。

  再看第5行的实例方法,为什么叫实例方法,明明没有self啊?这里要特别说明下,self只是约定俗成的写法,实际上随便写个什么字符串都可以的。因此第10行实例a调用实例方法,不会报错,程序正常


执行。

  第11行类A调用本地方法,也是不会报错的。但如果类A调用实例方法就和第一节讲的报错了。

  类方法

  类方法有一个特点,就是这个方法必须要有@classmethod来修饰。和实例方法类似,至少也要传一个参数,约定俗称为cls,Python会自动将类本身绑定到这个参数上面。

  类方法通常使用类直接调用,也可以用实例调用(不推荐)。当实例调用的时候,Python会将实例的最底层类(即实例直接所属类)型传入cls参数中。

class A(object):

    name = 'I am Class A'


    @classmethod

    def class_method(cls, s):


      print(cls.name)# 可以访问类成员print(cls.name)   # 可以访问类成员

      print(f"class_method : {cls} :: {s}")


class B(A):

    name = 'I am Class B'


a = A()

b = B()

A.class_method('I am class')

a.class_method('I am instance')

B.class_method('I am B class')

b.class_method('I am b instance')



  如上代码,B类继承了A类,并复写了name属性,而此时A类中的方法就是类方法,有两个参数,一个是默认的类参数cls,还有一个普通入参。

  第14行,A类直接调用自己的类方法,默认将自己传入了cls,并将括号中的字符串传给了参数s,用得恰到好处。此时第6行打印“I am Class A”可以看出,cls确实是传的A。


  第15行用A的实例a调用类方法,会默认将a的直属类(也就是A)传到cls中,因此效果和A调用是一样的。

  第16行用继承类B调用的父类的类方法,既然是继承,那么程序传入的就是类B到cls中,由于B类中对name做了复写,因此第6行打印出来的就是“I am Class B”。

  第17行用继承类B的实例b调用的父类的类方法,按照上述规则,是传入的b的直属类到cls中,也就是将B传入了cls中,而不是A(这边要注意区别),因此和B调用是一样的。

  静态方法

  静态方法是使用@staticmethod修饰的方法,它不能访问任何类属性和类方法,因为它不含self或cls这些特殊参数,因此也无法访问类或实例中的成员。

  也就是说,Python没有给他绑定实例或者类,要想使用,只能当参数来传,所以在静态方法中的入参都是普通参数,严格来讲,上面说的本地方法应该也要写成静态方法。

class A(object):

    @staticmethod

    def static_method(a, b):

      print(f"static_method : {a} + {b}")


a = A()

A.static_method('aa', 'bb')

a.static_method('aa', 'bb')



  如上代码中,尽管第7行类A调用了方法,但是由于是静态方法,访问不了类属性,因此不会将类A传入所谓的cls中,静态方法中也没有cls这个参数,因此它的参数都是普通入参。

  第8行的实例调用也是和A一样的效果。

  所以逻辑上讲,类方法应当只被类调用,实例方法只被实例调用,静态方法两者都能调用,主要区别在于参数传递上的区别。

  实例方法悄悄传递的是self引用作为参数,而类方法悄悄传递的是cls引用作为参数。

  要记住几点

  1.实例调用实例方法和本地方法时,Python默认将实例本身作为第一个参数传入。

  2.实例调用类方法时,Python默认将实例的最底层类作为第一个参数传入。

  3.实例调用静态方法时,Python啥也不传,需要几个参数就要传几个参数。

  4.类调用类方法时,Python默认将类本身作为第一个参数传入。

  5.类调用非类方法时,Python啥也不传,需要几个参数就要传几个参数。




页: [1]
查看完整版本: Python类的多种方法你知道多少