Python-面向对象
# 开闭原则 对扩展开放,对修改关闭
面向对象
组织和构建代码逻辑的一种思路,面向对象是主流的一种编程范式而已,还有面向过程和面向函数编程范式,但在在Python中面向对象最为彻底,一切皆对象
与类相关的概念
类、实例 、类方法、类变量、实例方法、实例变量
类相关的关键字 class @ staricmethod classmethod property setter
类考虑的主体是什么?
1. 类考虑的是群体与群体的统计数据和公共行为
2. 对象考虑单个个体的特征数据和行为
什么是抽象?
移除细节,看主干,从众多的事物中抽出共同的、本质性的特征,舍弃其非本质的特征,总体归结4个字: 提取共性
类的作用是什么?
1. 封装和组织代码架构
2. 只定义不运行,一个模块一个或多个类,通过导入实例化使用
什么是类?
人以类聚,物以群分。考虑的是群体的特征,把群体的特征抽象出来形成单独的类,依据有的群体有那就其他的群体没有的界限进行群体分类,这就是类。
什么是实例?
我们不一样,这就说明同时身为人类这个大类,但我们身上的具体特征属性各不相同,也就是通过差异化数据填充到类中,从而实现实例化,考虑的是类中单个个体的具体的特性数据和行为,是一种粒度比类小的一种抽象
什么是类变量?
群体相关的统计特征数据,每个实例都共享这个数据
什么是类方法?
群体都具有的行为,可以对群体特征数据进行操作
什么是实例变量?
单个个体的特征数据,也是一种抽象,粒度比较小的抽象,通过填充不同的数据值,生成完全不同的实例对象
什么是实例方法?
单个个体的特征行为,对个体实例变量进行操作,是粒度比较小的抽象,赋予实例对象行为
Python 类整体架构
class ExtendClass:
pass
class ClassName(ExtendClass):
"""通过实例变量和实例方法前加 _ 前缀约定为私有"""
# 类变量
class_variable = class_value
def __init__(self):
"""初始化实例变量"""
# 调用父类中析构函数
super().__init__()
# 私有属性,约定外部不可访问
_variable = object_value
# 公有属性,外部可以访问
variable = object_value
pass
def func(self):
"""公有实例方法,约定外部可访问"""
pass
def _func(self):
"""私有实例方法,约定外部不可方法"""
# 调用父类方法
super().func()
pass
def __func__(self):
"""Python协议又被称为魔法方法,给对象增强属性,重要的鸭子类型的实现"""
pass
@classmethod
def func(cls):
"""类方法,有个@classmethod装饰器,只能访问类变量"""
pass
@staticmethod
def func():
"""静态方法,不需要访问任何类变量和实例变量"""
pass
@property
def func(self):
"""调用属性一样调用方法"""
pass
# 这只是类的架构图(伪代码)
类名命名规范:
1. 遵循变量名命名规范
2. 驼峰命名方式,首字母大写并且通过首字母大写区分单词
类变量和类方法特性
1. 同类的实例共享
2. 通过类方法进行访问和修改,当前也可以直接访问
class BeiMenChuiXue:
object_number = 0
@classmethod
def add_one_object(cls):
cls.object_number += 1
@classmethod
def get_object_number(cls):
return cls.object_number
if __name__ == '__main__':
bei_men_chui_xue = BeiMenChuiXue()
BeiMenChuiXue.add_one_object()
xi_men_chui_feng = BeiMenChuiXue()
BeiMenChuiXue.add_one_object()
# 通过类名和方法访问
print(BeiMenChuiXue.get_object_number())
print(BeiMenChuiXue.get_object_number())
# 通过直接访问
print(BeiMenChuiXue.object_number)
print(bei_men_chui_xue.__class__.object_number)
# 也可以通过实例访问,这个根实例属性查找策略相关
print(bei_men_chui_xue.get_object_number())
析构函数和实例方法特性
1. 当实例化对象的时候,会自动调用__init__函数,不需要显式调用
2. 如果显示调用__init__函数则相当于普通函数,除了能返回None,其他都不能返回
3. 如果__init__传递参数,则实例化对象的时候需要传递参数,约定实例变量和形参同名
4. 定义实例方法的时候,self必须作为第一个参数,其实是当前调用实例本身,Python中显胜于隐原则
5. 通过添加 _前缀约定为私有
class BeiMenChuiXue:
def __init__(self, name, age):
self.name = name
self.age = age
self._country = None
def get_name(self):
return self.name
def get_age(self):
return self.name
def _get_country(self):
return self._country
def set_country(self, country):
if country == self._get_country():
pass
else:
self._country = country
def user_country(self):
return self._country
if __name__ == '__main__':
bei_men_chui_xue = BeiMenChuiXue(name="北门吹雪", age=18)
print(bei_men_chui_xue.get_age())
print(bei_men_chui_xue.get_name())
bei_men_chui_xue.set_country("中国")
print(bei_men_chui_xue.user_country())
其实本质上,通过__双下划线进行约束实例变量和方法为私有方法,Python会将这个变量或实例方法前添加了__ClassName前缀,本质上还是能访问到的
class BeiMenChuiXue:
# def __get_name(self):
# print("北门吹雪")
def __init__(self, name):
self.__name = name
if __name__ == '__main__':
bei_men_chui_xue = BeiMenChuiXue("北门吹雪")
print(vars(bei_men_chui_xue))
print(bei_men_chui_xue._BeiMenChuiXue__name)
使用类的过程
1. 定义类
2. 实例类
3. 调用实例方法或类方法
相关概念理清:
1. 成员函数就是实例方法
2. 成员变量就是实例变量
静态方法
属于这个类的一部分,不访问类变量和实例变量的方法
class BeiMenChuiXue:
country = None
def __init__(self, name):
self.name = name
@staticmethod
def go_hello():
print("Hello World!")
if __name__ == '__main__':
bei_men_chui_xue = BeiMenChuiXue("北门吹雪")
bei_men_chui_xue.go_hello()
属性方法
可以像访问属性和属性赋值访问实例方法,必须先定义 property方法才能定义 setter方法,在 property方法的基础上, 以 property装饰的函数为基础
class BeiMenChuiXue:
country = None
def __init__(self, name):
self.name = name
@property
def get_name(self):
return self.name
@get_name.setter
def set_name(self, new_name):
self.name = new_name
pass
if __name__ == '__main__':
bei_men_chui_xue = BeiMenChuiXue("北门吹雪")
bei_men_chui_xue.set_name = "beimenchuixue"
print(bei_men_chui_xue.get_name)
Python super查找路径
super其实本质上和父类没有一点关系,查找__mro__属性(类名.mor())的下一个类,只要其中一个属性或多个属性符合,则调用这个类的方法和实例变量,而不再调用其他类中__init__方法,需要核心注意,并不是完全继承。
class Student: def __int__(self, age, school): self.name = age self.school = school class Person: def __init__(self, name, skin): self.name = name self.skin = skin class BeiMenChuiXue(Person, Student): def __init__(self, name, skin, age, school): print(BeiMenChuiXue.__mro__) # 这句会报错,因为 满足 name 和 skin的类是 Person类,就调用Person的析构函数__init__ # 但是Person的析构函数__init__没有对age和school进行初始化,所以报参数给多的错误 super().__init__(name, skin, age, school) if __name__ == '__main__': bei_men_chui_xue = BeiMenChuiXue(name="北门吹雪", skin='yellow', age=19, school="Python") print(vars(bei_men_chui_xue))
面向对象三大特性
1. 封装, 类变量、实例变量、类方法、实例方法放在了一个类中
2. 继承,Python支持多继承,不推荐,推荐使用单继承树,多继承使用Minix思想继承,继承的类之间完全隔离不相干
3. 多态,Python通过鸭子类型实现多态,上面的属性方法也是多态的一种,但更多的是Python协议实现多态,也被称为魔法方法
经验:
1. 类将数据和数据的操作放在了一起,刻画某些事物的特性,总体上是一种抽象,核心为特征和行为,考虑的方式是群体与群体的划分
2. 实例对象是类中个体与个体之间的抽象,同填充具体的数据生成具体的个体对象
3. 约定属性前面添加一个下划线为私有属性,虽然双下划线也可以,但很多的优秀的库都是如此写的,Python并没有真正意义上限制属性的访问
4. 变量刻画特征,方法刻画行为并改变特征变量
5. 类查找相关变量首先找实例变量,然后找类变量,最后去父类中去找,约定按 __mro__顺序找
6. 封装最基本的原则,接收定义复杂不接受调用复杂