1. 类变量
以一个简单的学生实例创建为例,实现每创建一个学生实例,学生数量就+1的功能,以下代码分析了对类变量两种访问方式的区别,第一种是通过实例来访问,第二种通过类本身来访问。
1.1 通过实例访问
# 记录类变量、类方法、静态方法的使用
class Student:
studentNum = 0 # 在类下面直接定义的变量是类变量,需要用类来访问类变量,也可通过实例来访问类变量(一般不推荐,容易出问题)
def __init__(self, studentNo, name, sex):
self.studentNo = studentNo
self.name = name
self.sex = sex
self.studentNum += 1
# 实例属性永远无法修改类属性,即不管创建多少学生实例,类中的studentNum永远为0
# 创建实例时,在实例变量中不存在studentNum,因此对于self.studentNum = self.studentNum + 1,从右往左看,每次访问studentNum时
# 都去类变量中找,每次都是0,执行了 +1 操作后最终结果每次都是1
studentA = Student('2021282170044', 'jiangwang', 'male')
studentB = Student('2021282170049', 'zhongliujun', 'male')
studentC = Student('2021282170052', 'longma', 'male')
print(f'Student.studentNum:{Student.studentNum}')
print(f'studentB.studentNum:{studentB.studentNum}')
print(f'studentC.studentNum:{studentC.studentNum}')
运行结果如下图所示:
1.2 通过类本身来访问
class Student:
studentNum = 0
def __init__(self, studentNo, name, sex):
self.studentNo = studentNo
self.name = name
self.sex = sex
Student.studentNum += 1 # 每创建一个实例就将类变量studentNum的数量 +1
studentA = Student('2021282170044', 'jiangwang', 'male')
studentB = Student('2021282170049', 'zhongliujun', 'male')
studentC = Student('2021282170052', 'longma', 'male')
print(f'Student.studentNum:{Student.studentNum}')
print(f'studentB.studentNum:{studentB.studentNum}')
print(f'studentC.studentNum:{studentC.studentNum}')
运行结果如下图所示:
2. 类方法
类方法需要用到装饰器 @classmethod,使用类方法替代构造方法是一种很重要的做法。例如在上述代码中,当输入形式较多时就可以构建一个类方法来解析输入,然后构建实例。
class Student:
studentNum = 0
def __init__(self, studentNo, name, sex):
self.studentNo = studentNo
self.name = name
self.sex = sex
Student.studentNum += 1 # 每创建一个实例就将类变量studentNum的数量 +1
@classmethod
def parseString(cls, info): # 类方法第一个参数是类本身,一般使用 cls 代替
studentNo, name, sex = info.split(' ')
return cls(studentNo, name, sex) # 等价于Student(studentNo, name, sex)
studentA = Student('2021282170044', 'jiangwang', 'male')
studentB = Student('2021282170049', 'zhongliujun', 'male')
# 类方法需要使用类调用
studentC = Student.parseString('2021282170052 longma male')
print(f'Student.studentNum:{Student.studentNum}')
print(f'studentB.studentNum:{studentB.studentNum}')
print(f'studentC.studentNum:{studentC.studentNum}')
3. 静态方法
静态方法需要使用装饰器@staticmethod,静态方法不传入和类相关的参数,例如(self,cls),静态方法和类没有必然的依赖关系,只是单纯地存在于类中,下面以一个获取学号长度的简单示例作为展示。
class Student:
studentNum = 0
def __init__(self, studentNo, name, sex):
self.studentNo = studentNo
self.name = name
self.sex = sex
Student.studentNum += 1 # 每创建一个实例就将类变量studentNum的数量 +1
@classmethod
def parseString(cls, info): # 类方法第一个参数是类本身,一般使用 cls 代替
studentNo, name, sex = info.split(' ')
return cls(studentNo, name, sex) # 等价于Student(studentNo, name, sex)
@staticmethod
def studentNo_len(studentNo):
return len(studentNo)
studentA = Student('2021282170044', 'jiangwang', 'male')
studentB = Student('2021282170049', 'zhongliujun', 'male')
# 类方法需要使用类调用
studentC = Student.parseString('2021282170052 longma male')
print(f'studentC_studentNo:{studentC.studentNo}\nstudentC_studentNo_len:{Student.studentNo_len(studentC.studentNo)}')
运行结果如下图所示: