Python面向对象编程
基础
名词
类:就是具有相同属性和功能的一类事物。 对象:就是类的具体表现。 面向对象思维:要自己建立对象,自己建立场景,你就是面向对象世界中的上帝,你想让你的车干嘛就干嘛,你想让人干嘛就干
程序的对象对应现实中具体的事务(看得见摸得着的东西都算) 现实中的事务转换到电脑上变成程序 世间万物的一切皆对象 看得见摸得着的东西都是对象,只要是对象就能转换到计算机中以代码的形式表现
面向过程 : 想要一个结果 写代码 实现计算结果 面向对象开发 : 有哪些角色 角色的属性和技能 两个角色之间是如何交互的
优点:
- 面向对象编程:是一类相似功能函数的集合,使你的代码更清晰化,更合理化
- 面向对象,要拥有上帝的视角看问题,类其实就是一个公共模板(厂房),对象就从具体的模板实例化出来
类和对象之间的关系?
- 类是一个大范围 是一个模子 它约束了事物有哪些属性 但是不能约束具体的值
- 对象是一个具体的内容 是模子的产物 它遵循了类的约束 同时给属性赋上具体的值
小菜
对象:有下面几个对象
张一的手机
张二的手机
张三的手机
张四的手机
对象的集合–>共同特征:品牌、颜色、大小、价格 动作(能干啥):打电话、发微信,玩游戏
类别:手机、学生 学生:张一、张二、张三、张四 学生特征:姓名、性别、年龄、身高 学生动作:刷抖音、打电话 能做的动作有很多,在实际开发中,只列需要的动作 这些特征称为属性,动作称为方法
多个对象–>提取对象的共同特征和动作–>封装到一个类中,这就是面向对象
在代码中先定义类,在写其他 书写规则:约定俗成,类的首字母大写,多个单词使用驼峰体命名 例如:ValueError、TypeError等等
语法格式
在python3中,默认继承object类,所以书写的时候可以不写 语法:
class 类名():
属性:特征
方法:动作
class ShouJi(object):
pass
class ShouJi:
pass
实例化所经历的步骤
实例化所经历的步骤
-
类名() 之后的第一个事儿 :开辟一块儿内存空间 -
调用 init 把空间的内存地址作为self参数传递到函数内部 -
所有的这一个对象需要使用的属性都需要和self关联起来 -
执行完init中的逻辑之后,self变量会自动的被返回到调用处(发生实例化的地方) -
self可以修改,但是一般不改,约定俗成
面向对象基础方法
1、创建手机类模板
class ShouJi:
pass
print(ShouJi)
张一=ShouJi()
print(张一)
张二=ShouJi()
print(张二)
张三=ShouJi()
张四=ShouJi()
说明:
对象
- 对象===实例
- 给类中所有的属性填上具体的值就是一个对象或者实例
- 只有一个类,但是可以有多个对象都是这个类的对象
实例化
-
实例 = 类名() 首先开辟空间,调用init方法,把开辟的空间地址传递给self参数 init方法中一般完成 : 把属性的值存储在self的空间里 - 对象的初始化 self这个地址会作为返回值,返回给"实例" -
方法 : 定义在类里的函数,并且还带有self参数
-
实例变量 : self.名字
2、模板添加属性
class ShouJi:
品牌='华为'
张一=ShouJi()
print(张一)
print(张一.品牌)
张二=ShouJi()
print(张二)
print(张二.品牌)
张三=ShouJi()
张四=ShouJi()
3、模型修改 属性修改是模板中的不变,修改的是自己的属性,就好比王者荣耀中的个人所拥有的英雄 张一手机是苹果,不是华为
class ShouJi:
品牌='华为'
张一=ShouJi()
print(张一)
print(张一.品牌)
张一.品牌 = '苹果'
print(张一.品牌)
张二=ShouJi()
print(张二)
print(张二.品牌)
类中的属性
属性有类属性和对象属性,,在类中定义的属性叫做类属性(模型中的),在对象的属性叫做对象属性。是属于对象自己的 属性查找:先在对象自己的内存空间中查找,没有去类的内存空间中查找,不存在就报错 属性在自己内存空间找到,就不会再去模板的空间你去找
class Student:
name='张一'
age= 18
Student()
张一=Student()
2、动态对象属性 赋值操作永远作用的自己的内存空间,不会改变其他空间
class Student:
name='张一'
age= 18
张一=Student()
张一.age=20
print(张一.age)
3、类中的属性值如何修改 类中的属性值也叫做初始值,默认值 类属性通过类名去找
class Student:
name='张一'
age= 18
Student.name=20
print(Student.name)
类中的方法
类
类:类有什么属性,但不知道属性的值 对象:明确属性的值 python的数据类型属于类,内置的类 变量名=xx数据类型的对象 所以在python中一切皆对象,对象的类型就是类 所有的对象都有一个类型,class A实例化出来的对象的类型就是A类
类的成员和命名空间
class A:
def __init__(self):pass
def fu1(self):pass
def fu2(self):pass
def fu3(self):pass
国家='中国'
print(A.__dict__)
print(A.国家)
总结: 类中的变量是静态变量 对象中的变量只属于对象本身,每个对象有属于自己的空间来存储对象的变量 当使用对象名去调用某一个属性的时候会优先在自己的空间中寻找,找不到再去对应的类中寻找 如果自己没有就引用类的,如果类也没有就报错 对于类来说,类中的变量所有的对象都是可以读取的,并且读取的是同一份变量
__init__魔术方法
前面有__,后面__的都是魔术方法:__ 名字__() init:初识的、初始化 创建对象之后,系统默认执行动作,不需要你调用
手机1在实例化的过程所进行的操作: 1、寻找内存空间是ShouJi类的地址 2、使用ShouJi类创建对象,开辟一块内存空间,与ShouJi类一样 3、对象创建完之后,去ShouJi类中找有没有__init__方法,没有的话,将内存空间给对象手机1,空间创建完成, 4、有__init__,则会进入__init__方法,执行里面的动作 5、__init__中的self得到的是对象的内存空间的地址 6、__init__执行完里面的方法在赋值给对象手机1
init:保证每个对象都存在里面的额属性
class ShouJi:
def __init__(self):
self.pinPai='华为'
self.jiaGe=1000
def call(self):
print('正在打电话')
print('价格:',self.jiaGe)
手机1=ShouJi()
手机1.jiaGe=2000
手机1.call()
对象方法
1、对象方法,固定参数
class Student:
def __init__(self):
self.name='张一'
self.age=18
def eat(self):
print('{}正在吃饭'.format(self.name))
print('今年{}岁'.format(self.age))
st1=Student()
st1
st1.eat()
2、属性动态变化,魔术方法传参 外界传递的是什么就是什么
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print('{}正在吃饭'.format(self.name))
print('{}今年{}岁'.format(self.name,self.age))
st1=Student(name='李四',age=20)
st1.eat()
创建对象的时候传递参数,会系统传递到init中,这些解释性自动去完成,传递的参数由模板中定义
3、普通方法带参数
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self,food):
print('{}正在吃饭,吃的{}'.format(self.name,food))
print('{}今年{}岁'.format(self.name,self.age))
st1=Student(name='李四',age=20)
st1.eat('烧烤')
4、同级的方法可以相互调用,通过self.方法名()
def eat(self):
print('吃饭了')
def run(self):
print('跑步中')
self.eat()
类方法
通过装饰器来添加,在普通方法上添加@classmethod就是类方法 类方法属于类 普通方法,依赖对象存在,类方法不依赖对象,由类去调用 类方法里面的参数是cls,是class的简写 传参跟init用法一样
特点: 1、类方法定义需要@classmethod装饰器,传递的不是对象,而是类 2、类方法中的参数cls不是对象,而是类 3、类方法只能使用类属性,里面不能出现对象属性 4、可以不创建对象,通过类名来调用,调用方法:类名.属性名() 5、类中不能使用普通方法 6、类有自己的私有属性
作用: 只能访问类方法和类属性,所以在创建对象前,完成某些动作
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self,food):
print(6)
@classmethod
def xueXi(cls):
print(cls)
Student.xueXi()
类的私有属性
一般用于私有化,例如性别,年龄等 只有在我的这个范围才能修改,别人改不了 语法:在属性前面:__age=18,这种的就变成私有的了
1、私有方法创建 正常:未私有化之前
class Student:
__age=18
def show(self):
print('>>>:',Student.age)
print(Student.age)
私有化时候,私有之后外部无法调用
class Student:
__age=18
def show(self):
print('>>>:',Student.age)
print(Student.age)
2、那如何操作呢 没有对象,通过类方法(装饰器)来操作,查看修改都是
class Student:
__age=18
@classmethod
def updata(cls):
print('年龄修改:')
cls.__age=20
@classmethod
def show(cls):
print('修改后的年龄:',cls.__age)
Student.updata()
Student.show()
静态方法
静态方法:类似于类方法,依赖于装饰器 1、需要装饰器装饰@staticmethod装饰 2、装饰的函数不需要参数,cls参数,self参数,可以自定义参数 3、静态方法只能访问类的属性、方法,对象的无法访问 4、加载时机同类方法一样
class Student:
__age=18
@classmethod
def updata(cls):
print('年龄修改:')
cls.__age=20
@classmethod
def show(cls):
print('修改后的年龄:',cls.__age)
@staticmethod
def static():
print('我是静态方法')
print(Student.__age)
Student.static()
加装饰器有参数是类方法,加装饰器没有参是静态方法 装饰器跟类差不多,但是没有cls参数
一、类方法与静态方法的异同: 不同: 1、装饰器不同 2、类方法有参,静态方法无惨 相同: 1、只能访问类的属性与方法,对象的无法访问 2、都可以通过类名访问调用 3、都可以在创建对象之前使用,不依赖于对象
二、普通方法与类方法、静态方法的不同 不同: 1、没有装饰器 2、需要对象,永远依赖于对象,每个普通方法都有一个self,代表对象本身 3、只有创建了对象(实例化)才可以调用普通方法,否则无法调用
特性
三大特征:封装、多态、继承
继承
不同的类中,有很多相同的方法,代码重复性高
- 继承就是解决重复的
- 继承之后,子类可以使用父类中的:方法、静态变量
- 子类和父类的方法重名的时候,我们只使用子类的方法,而不会去调用父类的方法了,就近选择,优先自己
- 子类想要调用父类的方法的同时还想执行自己的同名方法
在子类的方法中调用父类的方法:父类型.方法名()
class B(A):pass
class ShouJiA:
def __init__(self):
self.pinPai='华为'
self.jiaGe=1000
def call(self):
print('正在打电话')
class ShouJiB(ShouJiA):
pass
shouji=ShouJiB()
print(shouji.jiaGe)
多继承
继承:儿子继承爹把爷爷也加进来,不断往上继承 单继承可以继承N个
class D:
def func(self):
print('in D')
class C(D):pass
class A(C):
def func(self):
print('in A')
class B(A):pass
B().func()
多继承:有好几个爹
class B:
def func(self):print('in B')
class A:
def func(self):print('in A')
class C(B,A):pass
C().func()
一个类有多个父类,在调用父类方法的时候,按照继承顺序,先继承的就先寻找
写代码的时候,是先有的父类还是先有的子类? 在加载代码的过程中 需要先加载父类 所以父类写在前面
多继承的继承顺序问题
只要继承object类就是新式类 不继承object类的都是经典类
- python3 所有的类都继承object类,都是新式类
- 在py2中 不继承object的类都是经典类,继承object类的就是新式类了
- 经典类 :在py3中不存在,在py2中不主动继承object的类
在py2中
class A:pass
class B(object):pass
在py3中
class A:pass
class B(object):pass
单继承
在单继承方面(无论是新式类还是经典类都是一样的)
class A:
def func(self):pass
class B(A):
def func(self):pass
class C(B):
def func(self):pass
class D(C):
def func(self):pass
d = D()
多继承(钻石继承)
在经典类中,都是深度优先,总是在一条路走不通之后再换一条路,走过的点不会再走了 新式类在走到一个点,下一个点既可以从深度走,也可以从广度走的时候,总是先走广度,再走深度,广度优先
class A:
def func(self):
print('A')
class B(A):
pass
class C(A):
pass
class D(B,C):
pass
print(D.mro())
广度优先的算法:C3算法
算法的内容: 如果是单继承 那么总是按照从子类->父类的顺序来计算查找顺序 如果是多继承 需要按照自己本类,父类1的继承顺序,父类2的继承顺序,…
merge的规则 :如果一个类出现在从左到右所有顺序的最左侧,并且没有在其他位置出现,那么先提出来作为继承顺序中的一个;或 一个类出现在从左到右顺序的最左侧,并没有在其他顺序中出现,那么先提出来作为继承顺序中的一个
如果从左到右第一个顺序中的第一个类出现在后面且不是第一个,那么不能提取,顺序向后继续找其他顺序中符合上述条件的类
- 经典类 - 深度优先 新式类 - 广度优先
- 深度优先要会看,自己能搞出顺序来
- 广度优先遵循C3算法,要会用mro,会查看顺序
- 经典类没有mro,但新式类有
查看继承:新式类中有,经典类汇总不存在
class A:
def func(self):
print('A')
class B(A):
pass
class C(A):
pass
class D(B,C):
pass
print(D.mro())
多态
python当中处处是多态,一切皆对象 1、多态,一个类型表现出来的多种状态 同一事物有多种形态 可以再不考虑对象具体类型的情况下而直接使用对象
2、鸭子类型 Linux中的一切皆文件就是如此:鸭子类型
未完成,还有
|