回顾
- 使用面向对象组织代码,可以降低耦合度,其中类的创建使用
class
语句; - 构造函数的调用:
类名(调用实参)
,用来实例化(创建)一个对象; - 实例方法:描述类有哪些行为;
- 初始化方法:
def __init__(self, 形参列表):
- 析构方法:
def __del__(self):
- 实例属性:对象用于绑定自己数据的变量叫实例变量,也叫属性;
- 每个对象都具有特殊属性:
__dict__
和__class__
- 对象有 2 个常用的函数:
isinstance(obj, 类或元组)
type(obj)
一. 类变量
定义:
类变量是类的属性,此属性属于类,不属于类的实例;通常用来存储该类对象共有的数据。
说明:
- 类变量可以通过属性直接访问:
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
类变量可以通过属性直接访问:
>> Human.total_count += 1
>> Human.total_count
1
类变量可以通过类的实例直接访问:
>> human1 = Human('Alex')
>> human1.total_count
2
实例的 __dict__
属性存储了自定义的实例变量:
>> human1.__dict__
{'name': 'Alex'}
下面的做法将为当前的实例添加一个变量,并不是修改类变量:
>> human1.total_count = 100
>> Human.total_count
2
>> human1.total_count
100
>> human1.__dict__
{'name': 'Alex', 'total_count': 100}
实例对象的 __class__
属性绑定了创建它的类,可以使用下面的方式修改类变量的值:
>> human1.__class__.total_count = 100
>> Human.total_count
100
类的 __slots__
属性:
用来限定一个类创建的实例只能有固定的属性(实例变量),不允许对象添加列表以外的属性。以防止用户因错写属性的名称而发生程序错误。
例如:Student
类中使用 __slots__
类属性声明 - __slots__ = ['name', 'age']
,让 Student
创建的对象只能用 name
属性和 age
属性,不能有其它属性。
class Student:
"""示意__slots__属性的作用和用法"""
__slots__ = ['name', 'age']
def __init__(self, name, age):
self.name = name
self.age = age
运行结果:
>> s1 = Student('Alex', 22)
>> s1.age
22
>> s1.name
'Alex'
>> s1.country = "China"
...
AttributeError: 'Student' object has no attribute 'country'
二. 类方法
类方法:
用于描述类的行为,此方法属于类,不属于该类创建的实例;
说明:
- 类方法需要使用
@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
参数; - 静态方法只能凭借该类或类的实例来调用;
- 静态方法不能访问类变量和实例变量(属性);
- 静态方法仅仅是属于一个类,和普通的函数是一样的。
示例:利用类方法和静态方法重写学生类
class Student:
"""描述学生的信息"""
count = 0
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
self.__class__.count += 1
def print_info(self):
print("{}: age={}, score={}".format(self.name, self.age, self.score))
@classmethod
def get_stu_number(cls):
"""只访问类变量,使用类方法即可"""
return cls.count
@staticmethod
def average(students, kind):
"""不需要访问实例变量和类变量,仅仅是定义在类内的函数,使用静态方法即可"""
sum_kind = 0
for student in students:
sum_kind += student.__dict__[kind]
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.name.lower() == name.lower():
stu_list.remove(student)
cls.count -= 1
录入学生信息:
>> stu_list = Student.add_stu_info()
输入姓名:Alex
输入年龄:12
输入成绩:100
输入姓名:Bob
输入年龄:14
输入成绩:90
输入姓名:
>>
调用静态方法,计算平均成绩 / 年龄:
>> Student.average(stu_list, 'score')
95
>> Student.average(stu_list, 'age')
13
删除列表中的学生:
>> Student.get_stu_number()
2
>> Student.remove_student('Alex', stu_list)
>> Student.get_stu_number()
1
调用实例方法,打印剩下学生的信息:
>> iter_stu = iter(stu_list)
>> next(iter_stu).print_info()
Bob: age=14, score=90
>> next(iter_stu).print_info()
...
StopIteration:
四. 特性属性 @properity
作用:
用来模拟一个属性,通过 @properity
装饰器可以对模拟的属性赋值和取值加以控制,以实现其它语言所拥有的 getter
和 setter
功能。
方式一: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)
>> s.score
59
>> s.score = 100
>> s.score
100
>> s.score = 1000
...
ValueError:
方式二:@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
运行结果同上。