前言
今天说说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。这些方法和类相关,但是又不需要类和实例中的任何信息、属性等等。如果把这些方法写到类外面,这样就把和类相关的代码分散到类外,使得之后对于代码的理解和维护都是巨大的障碍。而静态方法就是用来解决这一类问题的。
比如我们检查是否开启了日志功能,这个和类相关,但是跟类的属性和实例都没有关系。