面向对象(类、封装)
一、类与实例对象
1). 类的定义与实例化
- 实例化之前先定义类,类名要大写 (解释性语言特点)
class Student:
# Python很奇葩:这里定义为静态数据变量
name = '哈哈大圣' # 静态数据属性:
def learn(self): # 函数属性
print('is learning')
def eat(self): # 函数属性
print('is sleeping')
- 实例化对象
stu1 = Student()
print(stu1)
2). 类内元素操作
- 查看类的名称空间
a = Student.__dict__
name = Student.__dict__['name']
learn = Student.__dict__['learn']
- 获取类的属性
name = Student.name # 等同于Student.__dict__['name']
learn = Student.learn # 等同于Student.__dict__['learn']
- 增加类的属性,可以增加成员属性,也可以增加函数属性;(解释性语言特点)
Student.county = 'China'
def like():
print("like")
Student.like = like
Student.like()
- 修改类的属性
Student.school = '双一流大学'
- 删除类的属性
del Student.county
del Student.like
3). 构造函数
-
__init__
: 用来为对象定制对象自己独有的特征- 此方法中定义才为实例变量
class Student: #定义的时候执行该类
school='双一流大学'
def __init__(self, name, sex, age):
self.Name=name
self.Sex=sex
self.Age=age
def learn(self):
print('is learning')
def eat(self):
print('is sleeping')
- 执行定义的构造函数
stu1=Student('王二丫','女',18)
# 等同于Student.__init__(stu1,'王二丫','女',18)
4). 类方法、普通方法以及数据属性
- 调用普通方法,方法所在的地址都是一样的
- 对象中的绑定方法与对象之间进行绑定,不同的对象相同的绑定方法所占的内存地址是不一样的。
- 通过.访问的数据属性,会先在对象命名空间找,没有就在类的命名空间找,在没有就在父类中去找,但不会到所在模块中去找了,这是类的特性
二、继承
1). Python中的继承
- 支持多继承,通过C3线性查找算法生成一个MRO列表,根据列表顺序查找
- 继承的语法
class A:
name = "A"
def func(self):
print("A func")
class B:
name = "B"
def func(self):
print("B func")
# 继承的写法
class C(A, B):
name = "C"
def func(self):
print("B func")
2). 派生
- 派生,重写父类的方法或者属性
- 案例
class Hero:
def __init__(self, name, life_count, attact_count):
self.name = name
self.life_count = life_count
self.attact_count = attact_count
def attact_enemy(self, enemy):
enemy.life_count -= self.attact_count
# 加个括号表示继承
class Galen(Hero):
# 当子类中重写了父类的方法之后,就会调用子类的方法,这就叫做派生
def attact_enemy(self):
print("攻击无效")
class Ruiwen(Hero):
pass
g1 = Galen("草丛伦",100,30) #生成一个对象
r1 = Ruiwen("瑞文妹妹",80,50)
g1.attact_enemy()
3). C3线性查找算法
- 经典类的查找方式
经典类.png
- 新式类 (Py3中的类) 的查找方式:C3线性查找算法
- 根据继承关系生成对应的图,根据相应的图算法确定顺序。
- 很明显,如果多个分支有共同的父类,会将此父类的遍历位置放在其他分支的深度优先遍历之后。
新式类.png
- 任何父类中查找的起始点为发起方法/数据属性的子类所在的内存空间。
temp = "temp"
class Hero:
def f1(self):
print("Hero's f1")
def f2(self):
print("Hero's f2")
self.f1() # 注意,这里又开始从对象中开始查找了
print(self.nice) # 注意,这里又开始从对象中开始查找了
print(temp) # 这个temp不是用.调用的,不和对象产生关系,所以查找的方式是普通的命名空间的规则
class Galen(Hero):
def __init__(self):
self.nice = "nice"
def f1(self):
print("Galen's f1")
g1 = Galen()
g1.f2()
"""
Hero's f2
Galen's f1
nice
temp
"""
- 查看父类
class Foo:
pass
print(Foo.__bases__) #查看父类
print(Foo.mro()) #打印MRO列表(经典类没有这个方法)
4). 子类中重用父类的方法属性
- 子类中重用父类的方法和属性有两种方式
- 指名道姓(不依赖继承)
-
super()
: (依赖继承,基于对象所产生的MRO列表)
class Hero:
def __init__(self,nickname, life_value, aggresivity):
self.nickname = nickname
self.life_value = life_value
self.aggresivity = aggresivity
def attack(self, enemy):
enemy.life_value -= self.aggresivity
class Garen(Hero):
camp='Demacia'
def __init__(self, nickname, life_value, aggresivity):
# 依赖性继承的方式,py3中的简写方式(找MRO)
super().__init__(nickname, life_value, aggresivity)
def attack(self, enemy):
# 指名道姓重用父类的方法,不依赖于继承
Hero.attack(self, enemy)
print('from Garen Class')
class Riven(Hero):
camp='Noxus'
g = Garen('草丛伦',100,30)
r = Riven('锐雯雯',80,50)
三、组合
1). 组合概述
- 组合描述的是 has a 关系
- 对于类数据属性,通过实例对象“.”的方式进行数据子元素的增删改,如果没有实例变量则会找静态变量。
- 通过
实例.数据属性 = ?
这种形式,则此数据属性为对象属性,非静态的。
import datetime
class Person:
def __init__(self,name,gender,date):
self.name = name
self.gender = gender
self.date = date
self.age = self.calculate_age()
def calculate_age(self):
time_lag = datetime.datetime.now().year - self.date.date_struct.year
return time_lag
class Student(Person):
course_list = [] # 静态变量
def __init__(self,name,gender,date,course):
super().__init__(name,gender,date)
Student.course_list.append(course) # 这么写了就成了静态变量了
def learning_course(self):
print("%s is learing!" % self.name)
class Teacher(Person):
pass
class Date:
def __init__(self,year,month,day):
self.date_struct = datetime.datetime.now().replace(year=year,month=month,day=day)
def show_info(self):
print("%s年%s月%s日" % (self.date_struct.year,self.date_struct.month,self.date_struct.day))
d1 = Date(1996, 12, 12)
s1 = Student("a", "male", d1, "python")
# 通过对象直接增删改,对象没有则找静态变量
s1.course_list.append("python进阶")
# 直接赋值,数据属性属于对象。
s1.course_list = ["art"]
# 通过组合的方式调用了其他类中的属性(组合关系,非继承关系)就是有的关系
s1.date.show_info()
网友评论