封装
数据角度
(1) 定义:将一些基本数据类型复合成一个自定义类型。
(2) 优势:
– 将数据与对数据的操作相关联。
– 代码可读性更高(类是对象的模板)。
行为角度
(1) 定义:
向类外提供必要的功能,隐藏实现的细节。
(2) 优势:
简化编程,使用者不必了解具体的实现细节,只需要调用对外提供的功能。
设计角度讲
(1)分而治之-- 将一个大的需求分解为许多类,每个类处理一个独立的功能。 – 拆分好处:便于分工,便于复用,可扩展性强。
(2) 变则疏之-- 变化的地方独立封装,避免影响其他类。
(3) 高 内 聚-- 类中各个方法都在完成一项任务(单一职责的类)。
(4) 低 耦 合 – 类与类的关联性与依赖度要低(每个类独立),让一个类的改变,尽少影响其他类。
这里提下私有成员:
– 作用:无需向类外提供的成员,可以通过私有化进行屏蔽。
– 做法:命名使用双下划线开头。
– 本质:障眼法,实际也可以访问。
私有成员的名称实际上被修改为:类名__成员名,可以通过__dict__属性查看。
class MyClass:
def __init__(self, data,motto):
self.__data = data
self.__motto = motto
def __stu01(self):
print("stu01收到!!!")
m01 = MyClass(10,"吃苦趁现在")
# print(m01.__stu01) # 无法访问 AttributeError: 'MyClass' object has no attribute '__stu01'
# print(m01._MyClass__data)
print(m01.__dict__) # {'_MyClass__data': 10, '_MyClass__motto': '吃苦趁现在'} 都在这里面存了
# m01.__stu01() # 无法访问
# m01._MyClass__stu01()
属性
"""
属性 - 原理
作用:保护实例变量取值在有效范围内
步骤:
1. 私有化 实例变量
2. 提供公开的读取方法
3. 提供公开的写入方法
"""
class MYclass:
def __init__(self, name="", age=0):
self.name = name
# self.__age = age
self.set_age(age)
def get_age(self):
return self.__age
def set_age(self, value):
if value < 0:
value = 0
elif value > 120:
value = 120
self.__age = value
# 年龄: 0 ~ 120
ak = MYclass("阿珂", 9999)
ak.set_age(8888)
print(ak.name)
print(ak.get_age())
#代码的缺点:构造函数中我们看不出来有多少的实例变量了
#============================================================================================
"""
属性 - 过渡版本
"""
class Wife:
def __init__(self, name="", age=0):
self.name = name
# self.set_age(age)
self.age = age#这就叫属性了
def get_age(self):
return self.__age#这里必须是私有,不然的话外面的人就能找到他,那还怎么保护呀
def set_age(self, value):
if value < 0:
value = 0
elif value > 120:
value = 120
self.__age = value#把最终age放到了这
# 拦截(对实例变量的操作)
# 属性名 = property(读取方法名,写入方法名),语法就是这个语法,
# 这里我们是对age属性进行拦截,读取方法名,写入方法名这两个方法位置不能变,遵从这个语法就行
age = property(get_age,set_age)
ak = Wife("阿珂", 9999)
# ak.set_age(8888)
ak.age = 8888
print(ak.name)
# print(ak.get_age())
print(ak.age)
#===========================================================================================
"""
属性 - 终极版本
"""
class Wife:
def __init__(self, name="", age=0):
self.name = name
self.age = age#属性 这三个要一致
@property # age = property( age ) 读属性
def age(self):#这里age就叫属性名
return self.__age
@age.setter # age = age.setter( age ) 修改属性
def age(self, value):#age也是属性名
if value < 0:
value = 0
elif value > 120:
value = 120
self.__age = value
#属性的本质就是:保护实例变量,控制实力变量的范围。当age有了下面的两个def,他就是属性,没有它就是实例变量
#记住,属性他只对私有变量进行保护
ak = Wife("阿珂", 9999)
ak.age = 8888
print(ak.name)
print(ak.age)
#慢慢过渡
继承
继承,顾名思义
财产:钱不用孩子挣,但是孩子可以直接花.
皇位:江山不用太子打,但是太子可以坐.
编程:代码不用子类写,但是子类可以直接用.
#现有子类,再有父类,提取出来的父类,是在子类中都有其共性,都属于同一概念上的一样,把它提取出来成父类
#继承的行为
class Person:
def say(self):
print("说话")
class Student(Person):
def study(self):
print("学习")
class Teacher(Person):
def teach(self):
self.say()
print("教学")
print(isinstance(wk, Person)) # True
# 人对象 是一种 人类型
print(isinstance(p, Person)) # True
# 人对象 是一种 学生类型
print(isinstance(p, Student)) # False
# 学生对象 是一种 老师类型
print(isinstance(wk, Teacher)) # False
# 类型 是一种 类型的判断
# 学生类型 是一种 人类型
print(issubclass(Student, Person)) # True
# 人类型 是一种 人类型
print(issubclass(Person, Person)) # True
# 人类型 是一种 学生类型
print(issubclass(Person, Student)) # False
# 学生类型 是一种 老师类型
print(issubclass(Student, Teacher)) # False
内置函数
(1) isinstance(对象, 类型)
返回指定对象是否是某个类的对象。
(2) issubclass(类型,类型)
返回指定类型是否属于某个类型。
继承数据
class Person:
def __init__(self, name="", age=0):
self.name = name
self.age = age
# 子类有构造函数,会覆盖父类构造函数,好像它不存在
class Student(Person):
# 子类构造函数参数:父类+子类
def __init__(self, name="", age=0, score=0):
# 通过super()调用父类构造函数,它爸爸要啥,要 name,age
super().__init__(name, age)
self.score = score
class Teacher(Person):
def __init__(self, name="", age=0,salary=0):
super().__init__(name,age)
self.salary = salary
p = Person("悟空", 2) # 执行父类构造函数(self 指向父对象)
s = Student("悟空", 26, 100) # 执行子类构造函数 --> 执行父类构造函数(self 指向子对象)
# print(p.__dict__)
print(s.__dict__)
多态
(1) 定义:Python中,以双下划线开头、双下划线结尾的是系统定义的成员(这其实就是爹)。我们可以在自定义类中进行重写,从而改变其行为。(也就是说我们继承这个系统定义成员他爹,然后进行重新这个成员就可)
(2) __str__ 函数:将对象转换为字符串(对人友好的)
class Person(object):#Person的爸爸其实就是object
def __init__(self, name="", age=0):
self.name = name
self.age = age
def __str__(self):#重写object里面的函数,使其行为发生改变
return f"{self.name}的年龄是{self.age}"
wk = Person("悟空", 26)
# <__main__.Person object at 0x7fbabfbc3e48>
# 悟空的年龄是26
print(wk)
# message = wk.__str__()
# print(message)
。。。。这些都可以重新
#两点相加,一个传给self,一个other
class Vector2:
"""
二维向量
"""
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return "x是:%d,y是:%d" % (self.x, self.y)
def __add__(self, other):
# print(other)
return Vector2(self.x + other.x, self.y + other.y)
v01 = Vector2(1, 2)
# print(v01)
v02 = Vector2(2, 3)
print(v01 + v02)
"""
重写自定义函数
"""
#人去东北怎么去?
class Person:
def go_to(self, vehicle):
print("去东北")
if isinstance(vehicle, Vehicle):
# 先确定用法
vehicle.transport()
class Vehicle:
def transport(self):
pass
class Car(Vehicle):
def transport(self):
print("汽车在行驶")
class Airplane(Vehicle):
# 快捷键:ctrl + o
def transport(self):
print("飞机在飞行")
zl = Person()
bc = Car()
a = Airplane()
zl.go_to(bc)
zl.go_to(a)
zl.go_to("轮船")
#思想:去的方式有很多种,开车,坐飞机,轮船。。。。
#那么好,提取出来交通工具,把他们进行抽象,那么好,他们的行为都统一一下,都是运输,def运输(),抽象过后,我们就是为了把不同类型在某一行为上的统一,都成transport。这样的话,我们就重写了父类的transport,人只去调用运输就行了,就不用调用那什么飞机......
#由此我们可知,把子类概念一致的抽象一个父类,然后进行重写父类的方法,将子类的和父类行为进行统一,这样我们只调用父类就行