• 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啥也不传,需要几个参数就要传几个参数。

    【python学习】
    学Python的伙伴,欢迎加入新的交流【君羊】:740587468
    一起探讨编程知识,成为大神,群里还有软件安装包,实战案例、学习资料

  • 相关阅读:
    用于单细胞多组学整合的无监督拓扑对齐方法
    零时科技 || Tornado Cash中merkleTree和zk-snarks
    第十三届蓝桥杯大赛软件赛国赛B组C/C++(个人题解)
    pcl--第三节 关键点
    Excel实战-帮业务人员做道Excel题
    JavaSE-day01笔记
    静态时序分析(STA)学习记录
    Vue文件中css相关知识
    【管理咨询宝藏资料25】某能源集团五年发展战略报告
    MMKV源码解读与理解
  • 原文地址:https://blog.csdn.net/weixin_56659172/article/details/127817209