对象
- 对象
- 数据和功能的结合体,用于记录多个对象不同的数据和功能
- 对象独有的数据
- 往对象内添加该对象与众不同的数据
- 1.利用__dict__方法朝字典添加键值对
self1 = Student() self1.__dict__['name'] = 'jack' print(self1.name) 缺点:代码冗余,效率低下,添加一次就要输入一次- 2.封装为函数,添加独有的代码
def init(self,name) self.__dict__['name] = name stu0 = Student() init(stu0,'tom') print(stu0.__dict__) 缺点:每添加一次要重新用一个变量名,麻烦- 3.面对对象思想。使用init函数创建独有数据,将数据功能整合
1.先产生一个空对象 2.调用类里的__init__方法,把产生空对象当作第一个参数传入 3.将产生的对象返回出去 class Student: def __init__(self, name): self.name = name school = '清华大学' def choice_course(self): print('正在选课') stu1 = Student('jason') print(stu1) stu2 = Student('kevin') print(stu2)
- 往对象内添加该对象与众不同的数据
- 对象独有的功能
针对对象独有的方法,我们无法实现:
1.方法如果在全局里则不是独有的
2.方法如果在设置在类中也是公共的(谁都可以调)
所以python解释器为了解决此问题:
将定义在类中的函数默认绑定给对象(变为独有的方法)
class Person:
h_type = '人类'
# 让对象拥有独有的数据,这里独有的数据就是用户的名字
def __init__(self,name):
self.name = name
# 定义在对象里的类,称为方法
# 是多个对象独有的公共方法,对象来调用就会将对象本身当作第一个参数传入
def work(self):
print('%s正在写代码'%self.name)
def others(self,a,b):
print('其他人的工作完成了')
- 动静态方法
- 动静态方法是专门针对写在类体代码中的函数
- 绑定给对象的方法(直接在类体代码中编写)
1.对象调用自动将对象当作第一个参数传进去 2. 2.类的调用有几个形参就要传入相对于的实参 - 绑定给类的方法(静态方法【普通的函数】)
- 绑定给对象的方法(直接在类体代码中编写)
- 动静态方法是专门针对写在类体代码中的函数
面向对象
- 面向对象:
- 不同类型函数调用不同功能的过程就是面向对象
- 面向对象编程:
- 将数据和功能绑定到一起的操作
- 本质:只能彼此相互使用
- 面向对象编程思想:
- 对象是核心,提供了解决问题的方法
面向过程编程就是按流程办事得到结果,二者无优劣之分,经常混合使用。
面向对象的三大特性
继承
- 含义:
- 用来描述类与类之间数据的关系,类A继承了类B(拥有了类B里面所有的数据和功能)
- 目的:
- 为了节省代码的编写,可以继承一个类,也可以继承多个类
类的继承关系: 平时最常用的就是父类或者子类
被继承的类,我们称为,父类,基类或超类
继承了类的类,我们称为,子类或派生类
怎样实现:
class 类名1(类名2):
pass
1.定义类的时候要在类名1后面加括号
2.括号类名2里写的是要继承的类名
3.括号里可以继承多个父类,用逗号隔开
4.在括号里面,从左向右查找每个父类的属性
- 本质:
抽象:
将多个类共同的数据或功能抽取出来形成一个基类
继承:
从上往下收容各个基类里的资源
对象与类的区别
1.对象是数据和功能的结合体
2.类是多个对象相同的数据和功能的结合体
3.父类是多个类相同的数据和功能的结合体
# 类与父类主要的功能是为了节省代码
- 数据和方法找顺序
不继承
先从对象自身查找,没有再去产生对象的类中查找(对象>>>类)
单继承
先从对象自身查找,产生对象的类中查找,然后是一个个父类(对象>>>类>>>父类)
多继承
非菱形继承: 深度优先(单个分支走到底,在切换分支走到底)
菱形继承: 广度优先(先走单个分支,遇到分支汇总不走,走其他分支,最后再走汇总的分支)
(对象>>>类>>>父类)
封装
- 目的
- 把数据或功能隐藏,无法通过句点符点出来,然后通过特定接口才能访问
- 本质
- 在接口出添加了一些额外的操作,做了处理
- property伪装属性
- 将方法伪装为数据,可以点出来 property
@property # 将一个函数伪装为一个属性,让人看起来更加合理 @name.setter # 设置 @name.deleter # 删除
多态
- 含义
- 一种事物的多种状态
- 相同的功能应该有相同的名字,这样无论拿到哪个具体的名字,直接调用相同的功能即可
- 多态在以前数据类型内置方法就接触过(len方法)
- 一种事物的多种状态
反射
- 遇到关键字....对象....字符串就要使用反射
hasattr(): 判断对象是否含有某个字符对应的属性
getattr(): 获取对象字符串对应的属性
setattr(): 根据字符串给对象设置属性
delattr(): 根据字符串给对象删除属性
反射实战
魔法方法
- 定义
- 其实是类中定义的双下方法。无需调用,达到某个条件就会自动触发
- 魔法方法
双下init # 实例化对象时触发 双下str # 对象被执行打印操作触发,必须返回一个字符串,打印之后就该字符串 双下call # 对象加()调用触发 双下getattr # 对象获取不存在的属性名自动触发,返回对象获取不存在的属性名就会得到该对象 双下setattr # 对象操作属性值的时候自动触发>>>:对象.属性名=属性值 双下del # 对象在被删除(主动 被动)的时候自动触发 双下getattribute # 对象获取属性的时候自动触发 无论这个属性存不存在,既有__getattr__又有__getattribute__的时候,只走后面。 双下enter # 对象被with语法执行的时候自动触发 该方法返回什么 as关键字后面的变量名就能得到什么 双下exit # 对象被with语法执行并运行完with子代码之后,自动触发
类
-
概念
- 多个对象相同的数据和功能的结合体,用于记录多个对象相同的数据和功能
面向对象编程中 类仅仅是用于节省代码,对象才是核心 -
类的创建
关键字: class
# 类在定义阶段就会执行
模板:
class 类名:
学生对象公共的数据 (类体的代码)
学生对象公共的方法 (类体的代码)
查看名称空间的方法:
print(类名.__dict__) # 使用该方法查看名称空间 可以看成是一个字典
print(类名.__dict__['school']) # 使用字典的取值方式获取名字
print(类名.__dict__.get('choice_course')) # 使用字典的取值方式获取名字
在面向对象编程中,获取名称空间中的名字,可以采用句点符
类实例化对象:
类名.键名 = '修改后的值' # 修改键名对应的值
经典类与新式类
经典类: 不继承object或其子类的类(什么都不继承)
新式类: 继承了object或其子类的类
派生方法
- 子类里面定义的类与父类一摸一样的方法,并且进行了功能的拓展
- 子类继承了父类的功能并且做拓展
- 派生方法实战
元类
- 定义
- 产生类的类叫元类
- 之前使用type查看的是产生当前对象的类是谁
- 产生类的类叫元类
- 关键字
1.使用关键字class 2.利用元类type - 元类中的__init__用于实例化类
- 基本使用
- 1.继承了type的类才可以称为元类
class MyMetaClass(type): pass- 2.切换产生类的元类不能使用继承,要使用关键字metaclass声明
class MyClass(metaclass=MyMetaClass): pass - 元类进阶
- 元类可以控制类的产生过程也可以控制对象的产生过程
- 1.对象加()执行产生该对象类里面的双下call
- 2.类加括号执行产生该类的元类里面的双下call
- 实例化对象所有参数都必须采用关键字的形式
- 高度定制对象的产生过程:操作元类里面的__call__ - 高度定制类的产生过程:操作元类里的__init__ - 元类可以控制类的产生过程也可以控制对象的产生过程
双下new
- 产生类的步骤
- 1.产生一个空对象
- 2.自动触发__init__方法实例化对象
- 3.返回实例化完成的对象
- __new__方法专门用于产生空对象(外壳)
- __init__方法专门用于给对象添加属性(内脏)