目录:
预置实例属性 、 类变量 、 静态方法 @staticmethod 、 运算符重载
预置的实例属性:
dict属性:
用于绑定一个存储此实例自身变量的字典
class属性
用于绑定创建此实例的类
示例:
class Dog:
pass
dog1 = Dog()
print(dog1.__dict__)
dog1.color = "白色"
print(dog1.__dict__)
print(dog1.__class__)
用于类型判断的函数:
- isintance(obj, class_or_tuple) 返回这个对象obj是否是某个类的对象,或者某些类中的一个类的对象,如果是则返回True, 否则返回False
- type(obj) 返回对象的类
对象:
- 属性(对象拥有的名词) 用实例变量存储
行为(对象拥有的动作) 用方法表示
练习:
1. 定义一个类Huamn(人类)
有三个属性:
姓名: name
年龄: age
家庭住址: address (可以省略没有)
有如下方法:
show_info(self) 用来显示人的信息
update_age(self) 方法用来让这个人的年龄增加一岁
def input_human():
输入下此人的信息,姓名为空结束
def main():
docs = input_human()
for h in docs:
h.show_info() # 列出所有人的信息
for h in docs:
h.update_age() # 让所有人都长一岁
for h in docs:
h.show_info() # 再次列表所有人的信息
main() # 调用主函数运行
类变量
定义
类变量是类的属性,此属性属于类,不属于此类创建的实例
说明:
类变量,可以通过该类直接访问
类变量可以通过该类的实例直接访问
类变量可以通过此类的对象的 ‘class‘属性间接访问
示例:
class Human:
total_count = 0 # 类变量,用于记录对象的个数
print(Human.total_count)
h1 = Human()
print(h1.total_count) # 0 # 不会出错
Human.total_count = 1 # 修改类变量
h1.total_count = 2 #添加了自己的实例属性total_count
h1.__class__.total_count = 3 # 间接修改类变量
# 此示例示意 类变量的用余和使用方法
class Human:
total_count = 0 # 类变量,用于记录对象的个数
def __init__(self, name):
self.name = name
self.__class__.total_count += 1 # 人数加人
print(name, "对象创建")
def __del__(self):
self.__class__.total_count -= 1 # 总人数减1
print("当前对象的个数是:", Human.total_count) # 0
h1 = Human("张飞")
h2 = Human("赵云")
print("当前对象的个数是:", Human.total_count) # 2
del h2 # 或 h2 = None
print("当前对象的个数是:", Human.total_count) # 1
类的 slots 属性(有该属性类似java类,不可以动态添加属性)
作用:
限定一个类创建的实例只能有固定的属性(实例变量)
说明:
__slots__ 属性是一个列表,列表的值是字符串
含有__slots__属性的类所创建的对象没有__dict__字典
示例见:
# 此示例示意__slots__属性的用法
class Student:
# 限定此的类创建的对象只能有name和age两个属性
__slots__ = ['name', 'age']
def __init__(self, n, a):
self.name = n
self.age = a
s1 = Student("小张", 20)
# s1.Age = 21 # 此时是错写了age为Age, 会报错
# print(s1.__dict__) # 出错,因为没有__dict__字典
类方法 @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.get_v()) # 0
A.v = 1
print(A.get_v()) # 1
A.set_v(100)
print(A.get_v()) # 100
a = A() # 创建一个实例
a.set_v(200)
print(A.get_v()) # 200
静态方法 @staticmathod
定义:
静态方法是定义在类的内部的函数,此函数作用域是类的内部
说明:
静态方法需要使用@staticmethod装饰器定义
静态方法与普通函数的定义相同,不需要传入self和cls
静态方法只能凭借该类和实例来调用
静态方法不能访问类变量和实例变量
示例:
class A:
@staticmethod
def myadd(a, b):
return a + b
print(A.myadd(100, 200))
a = A()
print(a.myadd(300, 400))
练习:
修改之前的Human类 让此类能够记录此类生成的对象的个数,
用创建一个类方法get_human_count 来获取’人对象’的个数
继承 inheritance 和 派生 derived
什么是继承 / 派生
继承是从已有类中派生出新类,新类具有原类的数据属性和行为,并能扩展新的能力
派生就是从一个已有的类衍生出新类,在新的类上添加新的属性和行为
作用:
1. 用继承派生机制,可以将一些共有功能加在基类中,实现代码的共享
2. 在不改变超类的代码的基础上,改变原有的功能
名词:
基类(base class) / 超类(super class) / 父类(father class)
派生类(derived class) / 子类(child class)
单继承:
- 语法:
class 类名(超类名):
语句块 示例:
# 此示例示意单继承的语法及使用方法 class Human: # 人 def say(self, what): # 说话的行为 print("说: ", what) def walk(self, distance): # 走路的行为 print("走了", distance, "公里") h1 = Human() h1.say("今天天气不错!") h1.walk(5) print("-------------------") class Student(Human): # def say(self, what): # 说话的行为 # print("说: ", what) # def walk(self, distance): # 走路的行为 # print("走了", distance, "公里") def study(self, subject): print("正在学习", subject) s1 = Student() s1.say("今天晚饭吃什么?") s1.walk(3) s1.study("python") print('------------------------')
练习:
list类里只有append向末尾添加一个元素的方法,但没有向列表部添加元素的方法,试想能否为列表在不改变原有功能的基础上添加一个insert_head(n)的方法,在列表的头部添加元素class MyList(list):
def insert_head(self, element):
….
myl = MyList(range(3, 6)):
print(myl) # [3, 4, 5]
myl.insert_head(2)
print(myl) # [2, 3, 4, 5]继承说明:
任何类都直接或间接的继承自object类
object类是一切类的超类类内的 base属性
此属性用来记录此类的基类见: >>> help(builtins)
覆盖: override
什么是覆盖
覆盖是指在有继承派生关系的类中,子类中实现了与基类(超类)同名的方法,在子类实例调用方法时,实际调用的是子类中的覆盖版本,这种现象叫做覆盖
示例见:
# 此示例示意B类的work 覆盖A类的work
class A:
def work(self):
print("A类的work方法被调用")
class B(A):
def work(self):
print("B类的work方法被调用")
b = B()
b.work() # 子类已经覆盖了父类的方法
问题:
当覆盖发生时,子类对象能否调用父类中的方法?
super函数
语法:
super(type, obj) 返回绑定超类的实例(要求obj必须为type类型的实例)
super() 返回绑定超类的实例,等同于super(class, 实例的第一个参数), 且必须在方法内调用作用:
返回超类的实例,用超类实例来调用其自身的方法示例见:
# 此示例示意用super函数访问父类的覆盖方法 class A: def work(self): print("A类的work方法被调用") class B(A): def work(self): print("B类的work方法被调用") def doworks(self): # self.work() # 调用B类的 super(B, self).work() # 调用超类的方法 super().work() # 一样会调用超类的方法 # super(__class__, self).work() b = B() b.work() # B类的work方法被调用 print("-----以下用b调用覆盖版本的方法----") # A.work(b) # A类的work方法被调用 super(B, b).work() b.doworks()
显式调用基类的初始化方法:
class Human: def __init__(self, n, a): self.name = n self.age = a print("Human类的 __init__被调用") def show_info(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 show_info(self): super().show_info() print("成绩:", self.score) s1 = Student('张学友', 40) s1.show_info()
说明:
当子类实现了init方法后,父类的init方法将被覆盖,即不再会主动调用父类的init方法,会引起父类的属性得不到初始化,此时需要显式调用父类的初始化方法练习:
- 看懂学生管理系统划分模块的依据
- 添加保存文件和读取文件的代码
把字典改为对象来存储数据
(最好把学生对象的实例变量都封装在类内,让类外的函数最好不要操作这些实例变量)练习:
写一个Bicycle(自行车)类,有run(骑行)方法,调用时显示骑行里程km
class Bycycle:
def run(self, km):
print(“自行车骑行了”, km, “公里”)
再写一个电动自行车类EBicycle继承自Bicycle,添加电池电量valume属性,同时属有两个方法:
1. fill_charge(vol) 用来充电,vol 为电量(度)- run(km) 方法用于骑行,每骑行10km消耗电量1度,当电量消耗尽时调用Bicycle的run方法骑行
并显示骑行结果
主程序:
b = EBicycle(5) # 创建一个电动自行车,默认电量5度
b.run(10) # 骑行10km
b.run(100) # 骑行100km
b.fill_charge(6) # 充电6度
b.run(70) # 又骑行70km
- run(km) 方法用于骑行,每骑行10km消耗电量1度,当电量消耗尽时调用Bicycle的run方法骑行