python面向对象对象基础(一)内容回顾:
- 面向对象组织代码:降低耦合度(耦合度指各个对象之间的关联关系),界限分明;
- 使用class语句创建类;
- 构造函数的调用:类名(调用实参),用来实例化(创建)一个对象;
- 类中的3种方法:
- 实例方法:描述类有哪些行为;
- 初始化方法:def __init__(self, 形参列表):
- 析构方法:def __del__(self):
- 实例属性:每个对象用于绑定自己数据的变量叫实例变量,也叫属性;
- 每个对象都具有特殊属性:__dict__ && __class__
2 个函数
isinstance(obj, 类或元组)
type(obj)
一. 类变量
1. 概念
- 定义:类变量是类的属性,此属性属于类,不属于类的实例;
- 作用:通常用来存储该类对象共有的数据;
- 说明:
- 类变量可以通过属性直接访问:Human.total_count += 1;
- 类变量可以通过类的实例直接访问;
- 类变量可以通过此类的对象的__class__属性直接访问;
- 语法:
class 类名(继承列表):
类变量名 = 表达式
...
示例代码:
class Human:
"""示意类变量的用法,以及类和对象的关系"""
# 类变量,记录所有实例对象的个数
total_count = 0
def __init__(self, n):
"""对象在创建时,自动被调用"""
self.name = n
# 如果一个对象诞生,则将类变量total_count做+1操作
self.__class__.total_count += 1
def __del__(self):
"""对象在销毁时,自动被调用"""
self.__class__.total_count -= 1
if __name__ == "__main__":
# 类变量可以通过属性直接访问
Human.total_count += 1
print('Human类内的类变量 total_count =', Human.total_count)
# 类变量可以通过类的实例直接访问(实例对象的__class__属性绑定了创建它的类)
h1 = Human('Alex')
print('Human类内的类变量 total_count =', h1.total_count)
# __dict__属性存储了自定义的实例变量
print(h1.__dict__)
# 为当前的实例添加一个变量,并不是修改类变量
h1.total_count = 100
print('Human类内的类变量 total_count =', Human.total_count)
print('h1的实例变量 total_count =', h1.total_count)
print(h1.__dict__)
# 修改类变量的值
h1.__class__.total_count = 200
print('Human类内的类变量 total_count =', Human.total_count)
del h1
print('Human类内的类变量 total_count =', Human.total_count)
运行结果:
2. 类的__slots__属性
- 作用:限定一个类创建的实例只能有固定的属性(实例变量),不允许对象添加列表以外的属性;防止用户因错写属性的名称而发生程序错误;
- 说明:含有__slots__属性的类所创建的实例没有__dict__属性,即此实例不用字典来存储实例变量;
- 示例:
"""__slots__ = ['name', 'age']
此列表让Student创建的对象只能用name属性和age属性,不能有其它属性。
"""
class Student:
"""示意__slots__属性的作用和用法"""
__slots__ = ['name', 'age']
def __init__(self, name, age):
self.name = name
self.age = age
if __name__ == "__main__":
s1 = Student('Alex', 22)
print(s1.age)
print(s1.name)
# AttributeError: 'Student' object has no attribute 'country'
s1.country = "China"
备注:类的文档字符串是类内没有赋值给任何变量的字符串,由类的__doc__属性绑定。
二. 类方法
- 类方法:用于描述类的行为,此方法属于类,不属于该类创建的实例;
- 说明:
- 类方法需要使用@classmethod装饰器定义;
- 类方法至少有一个形参,第一个形参用于绑定类,约定为:'cls';
- 类实例和对象实例都可以调用类方法;
- 类方法不能访问实例属性和方法;
- 示例:
"""类方法的使用"""
class A:
"""docstring for A"""
# 类变量v
v = 0
def __init__(self):
# __init__定义的为实例变量,属于类的实例
self.my_v = 10000000
# 类方法需要使用@classmethod装饰器定义
@classmethod
# 类方法至少有一个形参,第一个形参用于绑定类,约定为:'cls'
def get_v(cls):
"""此方法为类方法,cls用于绑定调用此方法的类;此方法用于返回类变量v的值"""
return cls.v
@classmethod
def set_v(cls, value):
cls.v = value
if __name__ == "__main__":
# 通过类实例来调用类方法
print(A.get_v())
A.set_v(100)
print(A.get_v())
# 通过对象实例调用类方法
a = A()
print(a.get_v())
a.set_v(200)
print(a.get_v())
# 访问实例属性
print(a.my_v)
三. 静态方法
- 静态方法:定义在类内的函数,此函数的作用域是类的内部;
- 说明:
- 静态方法需要使用@staticmethod装饰器定义;
- 静态方法与普通函数定义相同,不需要传入self实例参数和cls参数;
- 静态方法只能凭借该类或类的实例来调用;
- 静态方法不能访问类变量和实例变量(属性)。
- 静态方法仅仅是属于一个类,和普通的函数是一样的
- 小结:实例方法,类方法,静态方法(面向对象编程);函数,和对象无关的,面向过程编程。
示例:利用类方法和静态方法重写学生类
"""用类来描述一个学生的信息
学生信息:name age score
要求:
1.将这些学生信息存于列表中,可以添加和删除学生信息;
2.打印学生的个数;
3.打印出所有学生平均成绩;
4.打印出所有学生的平均年龄;
建议用类变量存储学生的个数
"""
class Student:
"""描述学生的信息"""
count = 0
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
# 每创建一个对象,类变量count自动加1
self.__class__.count += 1
def get_name(self):
return self.name
def get_age(self):
return self.age
def get_score(self):
return self.score
@classmethod
def get_stu_number(cls):
"""只访问类变量,使用类方法即可"""
return cls.count
@staticmethod
def average(students, kind):
"""不需要访问实例变量和类变量,仅仅是定义在类内的函数,使用静态方法即可"""
sum_kind = 0
for student in students:
if kind == 'score':
sum_kind += student.get_score()
elif kind == 'age':
sum_kind += student.get_age()
average = sum_kind // Student.get_stu_number()
return average
@staticmethod
def add_stu_info():
"""一次性录入所有的学生信息,并以列表形式返回所有创建好的学生实例"""
students = []
while True:
name = input('输入姓名:') or 'q'
if name == 'q':
break
age = int(input('输入年龄:'))
score = int(input('输入成绩:'))
student = Student(name, age, score)
students.append(student)
return students
@classmethod
def remove_student(cls, name, students):
"""根据姓名删除列表中的学生"""
for student in students:
if student.get_name().lower() == name.lower():
stu_list.remove(student)
cls.count -= 1
else:
# for ... else ...语句
# 当学生列表为空时执行
print('学生信息不存在!')
if __name__ == "__main__":
# 录入学生信息
stu_list = Student.add_stu_info()
for s in stu_list:
print(s.get_name(), s.get_age(), s.get_score())
# 调用静态方法,计算平均成绩
score_average = Student.average(stu_list, 'score')
print(Student.get_stu_number(), '个学生的平均成绩为:', score_average)
# 调用静态方法,计算平均年龄
age_average = Student.average(stu_list, 'age')
print(Student.get_stu_number(), '个学生的平均年龄为:', age_average)
# 删除列表中的学生
name = input('请输入要删除学生的姓名:')
Student.remove_student(name, stu_list)
print(Student.get_stu_number())
for s in stu_list:
print(s.get_name(), s.get_age(), s.get_score())
运行结果:
四. 特性属性 @properity
- 实现其它语言所拥有的getter 和 setter 功能;
- 作用:用来模拟一个属性,通过@properity装饰器可以对模拟的属性赋值和取值加以控制;
- 用法一:score = property(get_score, set_score)
class Student:
def __init__(self, score):
self.__score = score
def get_score(self):
"""实现getter"""
return self.__score
def set_score(self, s):
"""实现setter"""
if 0 <= s <= 100:
self.__score = s
else:
raise ValueError
score = property(get_score, set_score)
s = Student(59)
print(s.score)
s.score = 88
print(s.score)
- 使用方式二:@property、@score.setter
class Student:
def __init__(self, score):
self.__score = score
@property
def score(self):
"""实现getter"""
return self.__score
@score.setter
def score(self, s):
"""实现setter"""
if 0 <= s <= 100:
self.__score = s
else:
raise ValueError
s = Student(59)
print(s.__dict__)
print(s.score)
s.score = 97
print(s.score)