浅谈python的classmethod staticmethod和实例方法


前言

今天说说python类中的类方法,静态方法和实例方法。


一、classmethod staticmethod

Python中3种方式定义类方法, 常规方式, @classmethod修饰方式, @staticmethod修饰方式。

import _ctypes


class A(object):
    def foo(self, x):
        print("executing foo(%s,%s)" % (self, x))
        print('self:', self)
    @classmethod
    def class_foo(cls, x):
        print("executing class_foo(%s,%s)" % (cls, x)) #executing class_foo(<class '__main__.A'>,5)
        print('cls:', cls) # cls: <class '__main__.A'>
    @staticmethod
    def static_foo(x):
        print("executing static_foo(%s)" % x) #executing static_foo(6)
        print("1")
a = A()
a.class_foo(5)

a.foo(10) #executing foo(<__main__.A object at 0x01E70850>,10)
#self: <__main__.A object at 0x01E70850> 打印的是实例化后的self在内存中的对象
id = id(a)
print(id) #35588176 打印实例化后的实例a在内存中的id地址
print(_ctypes.PyObj_FromPtr(int(id))# <__main__.A object at 0x021F0850>通过函数找到对应内存地址存储的对象。

a.static_foo(6)

这上面定义了三种方法,分别是静态方法,类方法和实例方法。
普通的self类方法foo()需要通过self参数隐式的传递当前类对象的实例; @classmethod修饰的方法class_foo()需要通过cls参数传递当前类对象;@staticmethod修饰的方法定义与普通函数是一样的。

我们这里顺便理解一下self参数和cls参数,self参数在实例化以后,代表的就是实例自身,我们可以通过上面的打印的内存地址和指向的对象就可以看出来。 cls代表的时钟是这个类自身,不是实例哦。

self和cls的区别不是强制的,只是PEP8中一种编程风格,self通常用作实例方法的第一参数,cls通常用作类方法的第一参数。即通常用self来传递当前类对象的实例,cls传递当前类对象。

二、绑定对象

foo方法绑定对象A的实例,class_foo方法绑定对象A,static_foo没有参数绑定。
a.class_foo(5)
executing class_foo(<class '__main__.A'>,5)
cls: <class '__main__.A'>

a.static_foo(5)
executing static_foo(5)

a.foo(5)
executing foo(<__main__.A object at 0x000001F2A8033A58>,5)
self: <__main__.A object at 0x000001F2A8033A58>

foo方法绑定对象A的实例,class_foo方法绑定对象A,static_foo没有参数绑定。

三、调用方式

import _ctypes


class A(object):
    def foo(self, x):
        print("executing foo(%s,%s)" % (self, x))
        print('self:', self)
    @classmethod
    def class_foo(cls, x):
        print("executing class_foo(%s,%s)" % (cls, x))
        print('cls:', cls)
    @staticmethod
    def static_foo(x):
        print("executing static_foo(%s)" % x)
        print("1")
class B(object):
    def __init__(self):
        self.a = 10
    def foo(self):
        print(self.a)
a = A()
a.class_foo(5)

a.foo(10)
id = id(a)
print(id)
print(_ctypes.PyObj_FromPtr(int(id)))

a.static_foo(6)
b = B()
A.foo(b,6)
A.foo(a,10)
#executing foo(<__main__.B object at 0x02410950>,6)
#self: <__main__.B object at 0x02410950>
#executing foo(<__main__.A object at 0x02410930>,10)
#self: <__main__.A object at 0x02410930>

关于调用方式,实例方法能被实例调用,一般也只能被实例调用,也能被类调用,但是在被类调用的时候需要传一个实例对象进去。

看上述的两种方法,都是使用类A调用了实例方法foo(),但是在传入实例对象的时候传入的对象一个是类A的实例化对象,一个是类B的实例化对象,说明只要是一个对象,都能正常调用。

import _ctypes


class A(object):
    def foo(self, x):
        print("executing foo(%s,%s)" % (self, x))
        print('self:', self)
    @classmethod
    def class_foo(cls, x):
        print("executing class_foo(%s,%s)" % (cls, x))
        print('cls:', cls)
    @staticmethod
    def static_foo(x):
        print("executing static_foo(%s)" % x)
        print("1")
class B(object):
    def __init__(self):
        self.a = 10
    def foo(self):
        print(self.a)
a = A()
# a.class_foo(5)

A.class_foo(5)
a.class_foo(10)
# executing class_foo(<class '__main__.A'>,5)
# cls: <class '__main__.A'>
# executing class_foo(<class '__main__.A'>,10)
# cls: <class '__main__.A'>

类方法均能被实例和类正常调用。

import _ctypes


class A(object):
    def foo(self, x):
        print("executing foo(%s,%s)" % (self, x))
        print('self:', self)
    @classmethod
    def class_foo(cls, x):
        print("executing class_foo(%s,%s)" % (cls, x))
        print('cls:', cls)
    @staticmethod
    def static_foo(x):
        print("executing static_foo(%s)" % x)
        print("1")
class B(object):
    def __init__(self):
        self.a = 10
    def foo(self):
        print(self.a)
a = A()
# a.class_foo(5)

A.static_foo(5)
a.static_foo(10)
# executing static_foo(5)
# 1
# executing static_foo(10)
# 1

静态方法也能正常被类和实例调用。
@staticmethod是把函数嵌入到类中的一种方式,函数就属于类,同时表明函数不需要访问这个类。通过子类的继承覆盖,能更好的组织代码。

在类A里面的实例方法foo(self, x),第一个参数是self,我们需要有一个A的实例,才可以调用这个函数。

当我们需要和类直接进行交互,而不需要和实例进行交互时,类方法是最好的选择。类方法与实例方法类似,但是传递的不是类的实例,而是类本身,第一个参数是cls。我们可以用类的实例调用类方法,也可以直接用类名来调用。

静态方法类似普通方法,参数里面不用self。这些方法和类相关,但是又不需要类和实例中的任何信息、属性等等。如果把这些方法写到类外面,这样就把和类相关的代码分散到类外,使得之后对于代码的理解和维护都是巨大的障碍。而静态方法就是用来解决这一类问题的。

比如我们检查是否开启了日志功能,这个和类相关,但是跟类的属性和实例都没有关系。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老师好,我是刘同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值