Python实例方法、静态方法和类方法详解(包含区别和用法)
类型对象按python的说法叫"type object"类型对象比较好理解;类的实例对象就是实例对象
#-*-encoding:utf-8-*-
class Person:
__counter = 0 #__开头的私有类属性,相当于C++的静态属性
#类的属性可在类内初始化,而C++类静态成员需要在类外全局作用域初始化
def __init__(self):
print(type(self))
type(self).__counter += 1 #type(self)返回self对象的类型对象
def func1(ziji):
print('execute func1(ziji) successed!')
#1、实例方法的第一个位置形参'self'只是个名字,不要求非得是'self'
#实例对象.func1()调用时默认将实例对象赋给实例方法的第一个位置形参
def GetClsAttr(self):
return Person.__counter
'''1、实例方法内可以访问类型对象,名字Person在实例方法所在的类内
local作用域,是可以找到的,由于不像C++预先编译连接,此处'Person'在
运行时才查找名字并获悉名字'Person'是个类型对象,并尝试访问类属性__counter
'''
def GetClsAttrNone():
return Person.__counter
@classmethod
def GetClsAttrCM(cls):
return cls.__counter #返回的类属性是值传递,不是引用传递
'''7、类型对象调用类方法能自动将类型对象绑定给类方法的第一个位置形参'cls'''
@staticmethod
def GetClsAttrSM():
return Person.__counter #名字查找到类型对象
@staticmethod
def GetClsAttrSM2(Vself, Vcls):
'''8、静态方法不绑定主调对象,
但由于运行时类型检查的关系,显式传入对象自然是可以的
'''
Vself.func1() #实例对象调用实例方法
Vcls.GetClsAttrCM() #类型对象调用类方法
return Vcls.__counter==Person.__counter #名字查找到类型对象进行引用或使用传入类型对象引用
def globalfunc():
print('heihei')
if __name__ == '__main__':
p = Person()
print('type(Person)', type(Person))
print('type(Person())', type(p))
print('实例对象p.GetClsAttr():', p.GetClsAttr())
#类实例对象调用类实例方法时自动将类实例对象传递给方法的第一个位置形参'self'
#print('类型对象Person.GetClsAttr():', Person.GetClsAttr())
'''TypeError: GetClsAttr() missing 1 required positional argument: 'self'
2、首先报类型错误而不是'对象没有属性GetClsAttr'的属性错误,说明类型对象可以调用
类实例方法只不过类型对象调用类实例方法时不会自动将类型对象自身传递给实例方法的
第一个位置形参'self',从而出错。但可以手动传入任意的变量给形参'self',如下:
'''
var0=0
print('类型对象Person.GetClsAttr(var0):', Person.GetClsAttr(var0))
'''3、类型对象调用类实例方法时显式传入任意的对象给形参'self',运行时只要传入的对象不
产生属性错误(访问了传入对象没有的属性)也能实现类型对象调用类实例方法
4、由此产生的思考是:将类实例方法的包括'self'在内的所有形参去掉就可以使用类型对象
直接访问(不用传任何对象)但此时这个方法既不像类方法(没有@classmethod装饰)
也不像实例方法(至少要有一个形参来接受默认的类实例自身),类实例将无法访问(因为
类实例调用方法时总是默认要传类实例自身到形参列表,这使得函数签名不匹配),如下:
'''
print('类型对象Person.GetClsAttrNone():', Person.GetClsAttrNone())
#print('实例对象p.GetClsAttrNone():', p.GetClsAttrNone())
#TypeError: GetClsAttrNone() takes 0 positional arguments but 1 was given
'''7、首先报形参不匹配的类型错误,说明解释器为类实例找到了空形参列表的方法
GetClsAttrNone(),类实例以方法的形式(obj.method())调用函数时首先查找类实例是否
有这个方法,若有则调用之,并且总是默认地将类实例自身作为第一个位置实参传递给形参
列表,这里触发参数列表不匹配的类型错误'''
'''5、要想让类型对象和类实例对象都能访问一个方法,可以将该方法声明为静态方法,
就是在方法前加@staticmethod装饰
'''
print('实例对象p.GetClsAttrSM():', p.GetClsAttrSM())
print('类型对象Person.GetClsAttrSM():', Person.GetClsAttrSM())
obj=Person()
print('实例对象Person.GetClsAttrSM2(obj, Person)):', Person.GetClsAttrSM2(obj, Person))
print(type(Person.GetClsAttr)) #<class function>
print(type(Person.GetClsAttrNone)) #<class function>
print(type(Person.GetClsAttrCM)) #<class method>
print(type(Person.GetClsAttrSM)) #<class function>
var0=Person.GetClsAttrCM()
var0=7 #返回的类私有属性是值传递,不是引用传递
print(Person.GetClsAttrCM()) # 1
var1=9
#print('int对象var1.GetClsAttr():', var1.GetClsAttr())
'''6、AttributeError: 'int' object has no attribute 'GetClsAttr'
直接报属性错误,这是显而易见的'''
python3.8执行输出:
haypin@ubt:~/Files$ python3.8 m07273.py
<class '__main__.Person'>
type(Person) <class 'type'>
type(Person()) <class '__main__.Person'>
实例对象p.GetClsAttr(): 1
类型对象Person.GetClsAttr(var0): 1
类型对象Person.GetClsAttrNone(): 1
实例对象p.GetClsAttrSM(): 1
类型对象Person.GetClsAttrSM(): 1
<class '__main__.Person'>
execute func1(ziji) successed!
实例对象Person.GetClsAttrSM2(obj, Person)): True
<class 'function'>
<class 'function'>
<class 'method'>
<class 'function'>
2
haypin@ubt:~/Files$