类属性
类属性是类的属性,此属性属于类,不属于此类的实例
作用:
通常用来存储该类型创建的对象的共有属性
说明:
类属性可以通过该类直接访问
类属性可以通过类的实例直接访问
类属性可以通过此类的对象的__class__属性间接访问
# 此示例示意类属性 class Human: '''人类''' total_count = 0 # 创建类属性,用来保存人类的个数 print(Human.total_count) # 0 # 类属性可以用类来直接访问 Human.total_count += 100 # 修改类属性 print(Human.total_count) # 100
类的文档字符串
类内第一个没有赋值给任何变量的字符串为类的文档字符串
类的文档字符串可以通过help函数查看
类的文档字符口中 可以用类的__doc__属性访问
示例: class Dog: '''这是用来描述小狗类型对象的类 此类有三个方法,吃,睡,玩...''' pass
类的 __slots__列表
作用:
限定一个类创建的实例只能有固定的实例属性(实例变量)
不允许对象添加一个列表以外的实例属性(实例变量)
防止用户因错写属性的名称而发生程序错误
说明:
__slots__属性是一个列表,列表的值是字符串
含有 __slots__ 列表的类所创建的实例对象没有__dict__属性即此实例不用字典来存储对象的实例属性
class Human: '''让Huam类型的对象只能有name 和 age属性, 不能有其它属性''' __slots__ = ['name', 'age'] def __init__(self, name, age): self.name = name self.age = age def show_info(self): print("姓名:", self.name, '年龄', self.age) h1 = Human('小张', 15) h1.show_info() # ??? 15 # h1.ago = 16 # 主动报错 h1.show_info() # ??? 15
类方法 @classmethod
类方法是用于描述类的行为的方法,类方法属于类,不属于该类创建的对象
说明:
类方法需要使用@classmethod装饰器定义
类方法至少有一个形参,第一个形参用于绑定类,约定写为'cls'
类和该类的实例都可以调用类方法
类方法不能访问此类创建的对象的实例属性
class A: v = 0 # 类属性 @classmethod def get_v(cls): '''类方法''' return cls.v @classmethod def set_v(cls, value): cls.v = value print(A.v) A.set_v(888) # 用类来调用类方法 print(A.get_v()) # 888 用类来调用类方法 a = A() print(a.get_v()) # 888 用对象来调用类方法 a.set_v(999) # 用实例对象来调用类方法 print(A.get_v()) # 999 print(a.get_v()) # 999
静态方法 @staticmethod
静态方法是定义在类内部的函数,比函数的作用域是类的内部
说明:
静态方法需要使用@staticmethod装饰器定义
静态方法与普通函数的定义相同,不需要传入self实例参数和cls 类参数
静态方法只能凭借该类或类创建的实例调用
静态方法不能访问类属性和实例属性
class A: @staticmethod def myadd(a, b): return a + b print(A.myadd(100, 200)) a = A() print(a.myadd(3, 4))
继承(inheritance) 和 派生(derived)
继承是从一个已有的类中派生出新类,新类具有原类的数据属性和行为并能扩展新的行为
继承的目的是延续旧的类的功能
派生的目的是在旧类的基础上添加新的功能
作用:
用继承派生机制,可以将一些共有功能加在基类中,实现代码的共享
在不改变基类代码的基础上改变原有类的功能
名词:
基类/超类/父类
派生类/子类
单继承的语法:
class 类名(基类名):
语句块
单继承是指派生类有一个基类衍生出来的
class Human: def say(self, what): print("say:", what) def walk(self, distance): print("走了", distance, '公里') class Student(Human): def study(self, subject): print("正在学习:", subject) class Teacher(Student): def teach(self, subject): print("正在教", subject) h1 = Human() h1.say("天气变暖了") h1.walk(6) s1 = Student() s1.walk(4) s1.say('有点小累') s1.study('Python') t1.teach("面向对象") t1.walk(3) t1.say('晚上吃点啥呢?') t1.study('转魔方')
继承说明:
Python3类都直接或间接的继承自object类
object类是一切类的超类
类的__base__属性
__base__属性用记录此类的基类
内建的类的继承关系见:
>>> help(__builtins__)
覆盖 override
覆盖是指在有继承关系的类中,子类中实现了与基类同名的方法,在子类的实例调用该方法时,实际调用的是子类中的覆盖版本,这种现象叫覆盖
作用:
实现和父类同名,但功能不同的方法
class A: def work(self): print("A.work被调用") class B(A): def work(self): '此方法覆盖了A.work方法' 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()返回实例间接调用其父类的覆盖方法
class A: def work(self): print("A.work被调用") class B(A): def work(self): '此方法覆盖了A.work方法' print("B.work被调用!") def super_work(self): self.work() # 调用自己的 super(B, self).work() super().work() # 功能等同于上一句 b = B() b.super_work() # b.work() # B.work被调用! # A.work(b) # A.work被调用 # super(B, b).work()
显式调用基类的初始化方法:
当子类中实现了__init__方法,基类的初始化方法并不会被调用此时需要用super来显式调用
class Human: def __init__(self, n, a): self.name = n # 姓名 self.age = a # 年龄 print("Human.__init__方法被调用") def infos(self): print("姓名:", self.name) print("年龄:", self.age) class Student(Human): def __init__(self, n, a, s=0): super().__init__(n, a) # 显式调用父类的初始化方法 self.score = s print("Student.__init__被调用!") def infos(self): super().infos() # 显式调用父类的infos() print("成绩:", self.score) s = Student("小张", 20) s.infos()
用于类的函数:
issubclass(cls, class_or_tule) 判断一个类是否继承自其它的类,如果此类class是class 或tuple中的一个派生子类则返回True, 否则返回False
如: class A: pass class B(A): pass class C(B): pass issubclass(C, B) # True issubclass(C, A) # True issubclass(A, B) # False issubclass(bool, (str, A, B, C, float)) # False issubclass(bool, (str, float, int)) # True