先看例子
class T:
def test_1(self):
print("test_1")
@property
def test_2(self):
print("property")
@classmethod
def test_3(cls):
print("cls")
@staticmethod
def test_4():
print("static")
t = T()
t.test_1()
t.test_2
t.test_3()
T.test_3()
t.test_4()
T.test_4()
概念上的区别
实例方法
定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法);
调用:只能由实例对象调用。
类方法
定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);
调用:实例对象和类对象都可以调用。
静态方法
定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;
调用:实例对象和类对象都可以调用。
什么场景下使用
- 注重安全和性能的,优先考虑staticmethod
- 当作属性来使用的,使用property
- 默认使用python实例的,使用普通方法
- 既可以使用类或实例来调用的,使用类方法
底层的实例
property的实现
class Property:
# 装饰器类的语法和装饰器方法类似,
# @property等价于roperty(...)
# 入参体现在初始化方法中
def __init__(self, func):
self.__name__ = func.__name__
self.getF = func
self.setF = None
pass
def setter(self, func):
self.setF = func
return self
def __set__(self, instance, value):
self.setF(instance, value)
pass
def __get__(self, instance, owner):
return self.getF(instance)
class A(object):
# 利用roperty像property一样定义属性
# 这里等价于name = roperty(name)
# 利用装饰器语法,name被赋值为roperty的实例
@roperty
def name(self):
print('get name1')
return self.__name
# 由于name被赋值为roperty的实例
# 为了演示上的区分,方法名为name1,实际开发中用name即可
# 以下等价于name1 = name.setter(name1)
@name.setter
def name1(self, n):
print('set name')
self.__name = n
a = A()
# 值得注意的是,经过装饰器语法后A.name已经是roperty对象(这里roperty对象既是一个装饰器又是一个描述器)
# 根据描述器的特性,a.name赋值会触发描述器的__set__方法,继而调用name属性定义的set方法
a.name = 'name1111'
# 根据描述器的特性,a.name读取会触发描述器的__get__方法,继而调用name属性定义的get方法
print(a.name)
classmethod 与staticmethod 的实现
class classmethod1(object):
def __init__(self, func):
self.sf = func
def __get__(self, instance, owner):
return lambda *args, **kwargs: self.sf(owner, *args, **kwargs)
class staticmethod1(object):
def __init__(self, func):
self.sf = func
def __get__(self, instance, owner):
return lambda *args, **kwargs: self.sf(*args, **kwargs)
class T(object):
def name(self):
print('instance.name')
@classmethod1
def className(cls):
print('{}.name'.format(cls))
@staticmethod1
def staticName(ipt):
print('{}.name'.format(ipt))
网友评论