类变量
类变量是类的属性,此属性属于类,不属于此类的实例
作用:
通常用来存储该类创建对象的共有属性
说明:
类变量可以通过该类直接访问
类变量可以通过类的实例直接访问
类变量可以通过此类的对象的__class__属性间接访问
示例:
# 此示例示意类变量的定义和用法
class Human:
total_count = 0 # 类变量,用来记录Human对象的个数
pass
print(Human.total_count) # 0 访问类变量
h1 = Human() # 创建一个对象
print(h1.total_count) # 0 借助于此类的实例访问类变量(类属性)
h1.total_count = 10000 # 这一步为实例添加实例属性
print(h1.total_count) # 10000
print(Human.total_count) # 0
#类变量可以通过此类的对象的__class__属性间接访问
h1.__class__.total_count += 1 # 等同于Human.total_count += 1
print(Human.total_count) # 1
# Human.total_count += 1 # 改变类变量
# print(Human.total_count) # 1
# 此示例示意用类变量来记录Human对象的个数
class Human:
total_count = 0 # 类变量,用来记录Human对象的个数
def __init__(self, n):
self.name = n
self.__class__.total_count += 1
print(n, '对象被创建')
def __del__(self):
print(self.name, '对象被销毁')
self.__class__.total_count -= 1
L = []
L.append(Human('张飞'))
L.append(Human('关羽'))
print("当前人物个数是:", Human.total_count)
del L[1]
print("当前人物个数是:", Human.total_count)
类的文档字符串
类内第一个没有赋值给任何变量的字符串为为类的文档字符串
类的文档字符串可以通过help()函数查看
类的文档字符串绑定在类的__doc__属性上
类的 __slots__列表
作用:
限定一个类创建的实例只能有固定的属性(实例变量)
不允许对象添加列表以外的实例属性(实例变量)
访止用户因错写属性名而发生程序错误
说明:
__slots__属性绑定一个字符串列表
含有__slots__属性的类所创建的实例对象没有__dict__属性,即此实例不用字典来存储对象的实例属性
示例:
# 此示例示意类内__slots__列表的用法和作用
class Human:
__slots__ = ['name', 'age']
def __init__(self, n, a):
self.name = n
self.age = a
def info(self):
print(self.name, '今年', self.age, '岁')
h1 = Human('小张', 8)
h1.info() # 小张 今年 8 岁
# h1.Age = 9 # <<--此处会出错。__slots__列表限定不能有此属性
h1.info() # 小张 今年 8 岁
类方法 @classmethod
类方法是用于描述类的行为的方法,类方法属于类,不属于类的实例对象
说明:
类方法需要使用@classmethod装饰器定义
类方法至少有一个形参,第一个形参用于绑定类,约定写为'cls'
类和该类的实例都可以调用类方法
类方法不能访问此类创建的对象的实例属性
示例:
class A:
v = 0 # 类变量(类属性)
@classmethod
def get_v(cls):
return cls.v # 用cls 访问类变量v
@classmethod
def set_v(cls, a):
cls.v = a
print('A.v = ', A.get_v()) # 调用类方法得到类变量的值
A.set_v(100)
print("A.v =", A.get_v()) # 100
print(A.v) # 100
静态方法 @staticmethod
静态方法是定义在类的内部的函数,此函数的作用域是类的内部
说明:
静态方法需要使用@staticmethod装饰器定义
静态方法与普通函数定义相同,不需要传入self实例参数和cls类参数
静态方法只能凭借该类或类创建的实例调用
静态方法不能访问类变量和实例变量
示例:
# 此示例示意静态方法的定义和使用
class A:
@staticmethod
def myadd(a, b):
return a + b
print(A.myadd(100, 200)) # 300
a = A()
print(a.myadd(300, 400)) # 700
继承 inheritance 和 派生 derived
什么是继承/派生
1. 继承是从已有的类中派生出新的类,新类具有原类的数据属性和行为,并能扩展新的行为
2. 派生类就是从一个已有的类中衍生出新的类,在新类的基本上添加新的属性和行为
为什么继承/派生
继承的目的是延续旧类的功能
派生的目的是在旧类的基础上改变原有的功能
名词:
基类(base class)/ 超类(super class)/ 父类(father class)
派生类(derived class) / 子类(child class)
单继承
语法:
class 类名(基类名):
语句块
说明:
单继承是指派生类由一个基类衍生出来新类
示例:
# 此示例示意单继承的定义方法和用法
class Human:
def say(self, what):
print("say:", what)
def walk(self, distance):
print("走了", distance, '公里')
class Student:
def say(self, what):
print("say:", what)
def walk(self, distance):
print("走了", distance, '公里')
def study(self, subject):
print("正在学习", subject)
class Teacher:
def say(self, what):
print("say:", what)
def walk(self, distance):
print("走了", distance, '公里')
def teach(self, subject):
print("正在教", subject)
h1 = Human()
h1.say('今天天气真好')
h1.walk(5)
s1 = Student()
s1.walk(4)
s1.say('感觉有点累')
s1.study('Python')
t1 = Teacher()
t1.teach("面向对象")
t1.walk(6)
t1.say('太累了,今天晚吃啥')
继承派生机制的作用:
1. 可以将一些共有功能加在基类中。实现代码的共享
2. 在不改变基类的基础上改变原有的功能
继承说明:
python3 任何类都直接或间接的继承自object类
object类是一切类的超类
类的 __base__ 属性
__base__属性用来记录此类的基类
python内建的类详见:
>>> help(__builtins__)
覆盖 override
什么是覆盖
覆盖是指在有继承关系的类中,子类中实现了与基类同名的方法,在子类的实例调用该方法时,实际调用的是子类中的覆盖版本,这种现象叫覆盖
示例:
# 此示例示意覆盖的含义及用法
class A:
def work(self):
print("A.work 被调用")
class B(A):
'''B类继承自A类'''
def work(self):
print("B.work被调用!!!")
b = B()
b.work() # B.work被调用!!!
a = A()
a.work() # A.work 被调用
调用方式:
基类名.方法名(实例, 实际调用传参,....)
super函数
super(cls, obj) 返回绑定超类的实例(要求obj必须为cls类型的实例)
super() 返回绑定超类的实例,等同于: super(__class__, 实例方法的第一个参数, 必须在方法内调用)
作用:
借助super()返回的实例间接调用父类的覆盖方法
示例:
# 此示例示意用super函数间接调用父类中覆盖版本的方法
class A:
def work(self):
print("A.work 被调用")
class B(A):
'''B类继承自A类'''
def work(self):
print("B.work被调用!!!")
def super_work(self):
# 调用B类自己的方work方法怎么调用
self.work()
# 调用父类的work怎么调用
super(B, self).work()
super().work() # 此种调用方式只能在实例方式内调用
b = B()
# b.work() # B.work被调用!!!
# super(B, b).work() # A.work 被调用
b.super_work()
# super().work() # 出错
显式调用基类的初始化方法
当子类中实现了__init__方法,基类的构造方法并不会被调用,此时需要显式调用
示例:
# 此示例示意显式调用初始化方法
class Human:
def __init__(self, n, a):
self.name = n # 姓名
self.age = a # 年龄
print("Human类的初始化方法被调用 ...")
def infos(self):
print("姓名:", self.name)
print("年龄:", self.age)
class Student(Human):
def __init__(self, n, a, s=0):
# super(Student, self).__init__(n, a)
super().__init__(n, a)
self.score = s
print("Stduent的初始化方法被调用...")
def infos(self):
super().infos() # 显式调用父类的方法
print('成绩:', self.score)
s1 = Student('张飞', 15, 80)
s1.infos()
课后习题:
1. 看懂学生信息管理系统的代码.理解实例方法的用法及实例变量封装的思想及好处
2. 写一个类Bicycle类,有run方法,调用时显示骑行的里程(km)
def Bicycle:
def run(self, km):
print("自行车骑行了", km, '公里')
再写一个类EBicycle,在Bicycle类的基础上添加电池电量volume属性,和两个方法:
1.fill_charge(vol) 用来充电 vol 为电量(度)
2. run(km) 方法每骑行10km消耗电量1度, 同时显示当前电量,当电量耗尽时,则调用Bicycle的run方法继续骑行
class EBicycle(Bicycle):
....
def fill_charge(self, vol):
'''充电'''
def run(self, km):
...
b = EBicycle(5) 新买的电动车内有5度电
b.run(10) # 电动骑行了10km还剩4度电
b.run(100) # 电动骑行了40km还剩0度电, 用脚登骑行了60km
b.fill_charge(10) # 充电10度
b.run(50) # 电动骑行了50km还剩5度电
想要看更多的课程请微信关注SkrEric的编程课堂