面向对象
2019-08-21 13:38:21 0 举报
AI智能生成
python知识点:面向对象
作者其他创作
大纲/内容
类的结构
1.变量部分:静态字段(静态变量).
私有静态字段:__变量名
公有静态字段
2.方法(函数)部分:动态方法(动态变量).
实例方法:func(self),通过对象调用
私有方法:__函数名,类内部调用
属性:@property:将方法伪装成属性,为了更合理.
应用于:类似BMI、面积这种看着像名词,但实际需要通过计算的
属性的改值:@属性化的方法名.setter(@age.setter),当对属性化的方法名改值的时候(p1.age = 26)触发执行
(知道就行了)属性的删除:@属性化的方法名.deleter,当见到del p1.age这个指令时触发执行
特殊方法(内置方法/
魔术方法/双下方法)
魔术方法/双下方法)
__new__:构造方法 开辟内存空间,产生并返回对象,通过类名+()触发
在什么时候执行呢?
在实例化过程中,在__init__之前执行
执行new 和 init的整个过程就是实例化过程
在实例化过程中,在__init__之前执行
执行new 和 init的整个过程就是实例化过程
面试题:写一个单例类****
__init__:初始化方法,此方法主要是给对象封装属性
__call__方法:通过实例化的对象()触发.
用类写装饰器的时候必用
用类写装饰器的时候必用
__item__系列:
# 和对象使用[]访问值有联系
# 在内置模块中,有一些特殊的方法,要求
对象必须实现getitem/setitem才能实现
# 和对象使用[]访问值有联系
# 在内置模块中,有一些特殊的方法,要求
对象必须实现getitem/setitem才能实现
__getitem__:obj['name'] 就会触发__getitem__方法,并将'name'传入此方法中
__setitem__
obj['name'] = 'alex' 就会触发
__delitem__
del obj['name'] 就会触发
__len__方法:len(对象) 触发
要求这个方法的返回值必须是int类型
__hash__方法: hash(对象) 触发
hash是一个算法,能够把某一个要存在内存里的值通过一系列计算,保证不同值的hash结果是不一样的
对同一个值在多次执行python代码的时候hash值是不同。但是对同一个值 在同一次执行python代码的时候hash值永远不变
__str__方法:print(对象)或者str(对象)或者格式化输出'%s' % 对象 触发
要求这个方法的返回值必须是str类型
__repr__方法:保持原型 repr(对象)或者格式化输出'%r' % 对象 触发
是__str__的备胎.
如果有__str__方法,那么 print()、%s、str()都先去执行__str__方法,并且使用__str__的返回值
当没有__str__时,print()、%s、str()也会触发__repr__方法
如果有__str__方法,那么 print()、%s、str()都先去执行__str__方法,并且使用__str__的返回值
当没有__str__时,print()、%s、str()也会触发__repr__方法
# 在子类中使用__str__,先找子类的__str__,没有的话要向上找,只要父类不是object,就执行父类的__str__
# 但是如果出了object之外的父类都没有__str__方法,就执行子类的__repr__方法,如果子类也没有,
# 还要向上继续找父类中的__repr__方法.
# 一直找不到 再执行object类中的__str__方法
# 但是如果出了object之外的父类都没有__str__方法,就执行子类的__repr__方法,如果子类也没有,
# 还要向上继续找父类中的__repr__方法.
# 一直找不到 再执行object类中的__str__方法
要求这个方法的返回值必须是str类型
__del__方法:析构方法 del 对象 触发 或者 代码块执行完(或者大型代码执行中途清理
不需要的对象空间),python解释器回收机制回收这个对象所占内存的时候自动触发
不需要的对象空间),python解释器回收机制回收这个对象所占内存的时候自动触发
应用:去归还或者释放在创建对象的时候借用的一些资源(例如文件、网络链接等)
__eq__方法:对象 == 对象 或者set去重时,某几个元素hash值相同后 触发
上下文管理器相关,对一个对象进行with操作时触发这两个方法
__enter__方法
__exit__方法
代码示例
类方法
@classmethod(cls): 通过类名调用的方法,他会将类空间传给cls
#对象调用类方法,传给cls的也是对象的所属类的类空间
#对象调用类方法,传给cls的也是对象的所属类的类空间
类方法的作用:就是想要类名调用,去操控这个公共模板的内容(属性,方法等)
应用场景:
1.类中,有些方法无需对象参与,是不需要传入对象的
2.对类的静态变量进行改变(通过对象只能查询、调用类中的静态变量,而没有增删改等其他操作)
3.(常用)继承中,父类获取子类的类空间 (子类通过类名执行父类的类方法,并将类名空间传给父类),这样就可以对子类的类空间中的所有内容为所欲为。(而另一种方法,通过实例化一个对象之后执行父类中的方法,来访问子类中的值,就只能查询,不能别的修改等)
静态方法
@staticmethod():不用传入类空间,对象空间的方法
存在意义:
1.代码块的整体性,将函数分类,清晰
2.复用性
私有成员
类的成员按照公有私有可以分为两种:私有成员,公有成员。
私有成员分为三种
私有类的静态属性
私有对象属性
私有方法
代码示例
私有成员:只可以本类中内部访问,不能在类外部以及派生类中访问。
(其实也可以访问,_A__age(),但工作中千万不能用!!)
(其实也可以访问,_A__age(),但工作中千万不能用!!)
空间,以及查找顺序
类名()会产生一个对象空间obj,此空间中有类对象指针,对象可以通过这个类对象指针找到从属的类。
对象查询属性:先从对象空间去找,对象空间没有,通过类对象指针去所属类去找
类查找顺序:先从本类去找,如果没有从父类去找,.......
类与类之间的关系
类与类之间原本没有关系,但是为了程序的拓展,
增加代码之间的耦合性,可以让类产生关系。
增加代码之间的耦合性,可以让类产生关系。
依赖关系
依赖关系是类与类之间耦合性最低的关系,就是将
一个类的类名或者对象传入到另一个类的方法中
一个类的类名或者对象传入到另一个类的方法中
关联,聚合,组合关系
给一个类的对象封装一个属性,这个属性是另个类的对象
实现,继承关系
实现也是继承关系,这个会在面向对象的三大特性中详细说明。
类的约束
方式一:提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错.
方式二:使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果.
反射
定义:在某个制定的命名空间中,用字符串数据类型的变量名来获取这个变量的值
四种方法:getattr、hasattr、setattr、delattr
应用getattr/hasattr
1.使用类来反射:调用静态属性、类方法、静态方法时推荐使用
类名.xxx == getattr(类名,'xxx') #xxx是方法的话就加个()执行
类名.xxx == getattr(类名,'xxx') #xxx是方法的话就加个()执行
# 反射查看属性
2.使用对象来反射:调用对象属性、普通方法时推荐使用
对象.xxx == getattr(对象,'xxx')
对象.xxx == getattr(对象,'xxx')
3.使用模块来反射:调用模块中的方法时使用
模块.函数名(各种参数) == getattr(模块,'函数名')(各种参数)
模块.函数名(各种参数) == getattr(模块,'函数名')(各种参数)
4.反射自己模块中的内容:需要先查找自己模块的名字(import sys 然后用sys.module查)
应用setattr/delattr
(很少用到)
(很少用到)
setattr:修改
a = A('alex')
a.name = alex_SB == setattr(a,'name',alex_SB)
a.name = alex_SB == setattr(a,'name',alex_SB)
delattr:删除
del a.name == delattr(a,'name')
类,对象的定义
类:具有相同属性和技能的一类事物.
定义一个类:class 类名(注意:类名首字母要大写)
类体
类体
对象:类的具体表现.具体的实实在在的一个实例
为什么要有面向对象
1,面向对象是将相关的功能(函数)的集合,让代码更加合理的分类。
2,站在上帝的角度去考虑问题,他实际是构造了一个公共模板,通过这个公共模板实例化N多个对象,使代码具有多样性,规范性。
面向对象在实例化时做的三个事情:
1.开辟一个空间,属于对象的
2.把对象的空间传给self,然后执行init
3.将这个对象的空间返回给调用者
类名的角度
操作类中的静态变量:
类名查询类中的所有内容(静态属性(变量),动态属性方法等):类名.__dict__
执行结果是个字典,可通过key查询单个的内容,但不能增删改
一般工作中用来查询类中的所有内容,而不用来查某一个内容
类名操作类中的某个公有静态属性(变量)(万能的.): 类名.字段名称
增:Person.money = '会利用货币'
删:del Person.mind
改:Person.money = '不会用钱'
查:print(Person.money)
先从类空间找,找不到再从父类中找
执行类中的方法: 类名.字段名称(给self传的位置参数)但工作中基本不用类名来调用类中的方法,除了两个特殊的:类方法 和 静态方法。
对象的角度
对象的形成以及执行流程:
对象的形成:类名+() #Person() 实例化对象/实例/对象
#对象与对象之间是相互独立的
对象形成的执行流程: #实例化的过程
1.类名+()产生一个实例(对象/对象空间)
2.自动执行类中的__init__方法,并将对象空间传给__init__中的self参数
3.执行具体的__init__代码,给对象封装相应的属性(用self.属性名 = 参数名,参数名是__init__中的位置参数)
对象操作对象中的静态变量
1.查询对象的所有属性:对象.__dict__
2.操作对象的某一属性(万能的.):对象.属性名
增:ret.high = 180
删:del ret.name
改:ret.age = 28
查:print(ret.hobby)
查询顺序:先从对象空间,找不到再从类空间,找不到再从父类中找...
对象查询类中的静态变量:对象.变量名(#对象操作类中的静态变量,只能查询,没有其他操作.即通过类名可以修改类中的静态变量,但通过对象就只能引用类中的静态变量,而不能修改)
对象调用类中的方法:对象.函数名(self)(#工作中,通过对象调用类中的方法,而不是通过类名)
面向对象的三大特性:
继承
单继承
单继承中经典类和新式类继承顺序都一样
执行父类的静态变量:
如果子类没有同名变量则可以直接 . 寻找
如果子类有存在与父类同名的静态变量则通过super().area,或者直接父类.变量名的方法查找
在子类中既执行本类又执行父类的方法
父类名.父类方法名(self,父类此方法所需参数)
super().父类方法名(父类此方法所需参数)
只执行父类的方法:子类中不能定义同名的方法。
多继承(钻石继承)
经典类: 深度优先,一条路走到黑.
深度优先/广度优先的前提是:只继承两类
新式类:广度优先:一条路走到倒数第二级,判断,如果其他路能走到终点,则返回走另一条路.如果不能,则走到终点.
C3算法,通过类名.mro()方法可以查出父类的继承顺序。
C3算法,通过类名.mro()方法可以查出父类的继承顺序。
新式类的继承具体算法链接:
继承的优点:
1,提高代码的复用性。
2,提高代码的维护性。
3,让类与类产生关系,使得代码更具关联性,增加耦合性(双刃剑)。
继承的缺点:
类的耦合性增强了。
封装
给对象封装属性
给一个类封装静态变量及方法
私有成员:私有静态字段,私有动态方法,私有对象属性:__变量
私有成员:类只要加载到内存,他会将所有的私有成员变成: _类名__变量名
何处调用: 只能在类内部调用,不能在派生类或者类外部调用
多态
Python默认支持多态,即一个变量可以代指不同的类型,不用规定死。比如函数的形参 func(a): 对于形参a来说,他可以代指任意数据类型。Python处处是多态
python崇尚鸭子类型:长得像鸭子,他就是鸭子。
接口类/抽象类
在Python中两者是一样的
1.归一化设计
2.制定一个规范,凡是继承我类的子类,必须用我规定的方法
进阶知识补充
1.dic字典的寻址机制
dic[key]。使用hash算法,对key值进行hash(key),得到的hash值指向key所对应的value存
储的内存地址,从而直接取得value。因此,字典的寻址是一次查找,所以很快
储的内存地址,从而直接取得value。因此,字典的寻址是一次查找,所以很快
2.set集合的去重机制
针对s集合里的每一个元素进行hash,按得到的hash结果找内存地址对元素进行储存,当得到两个相同hash结果时,
会调用eq判断两个元素值是否相等(==),若值相等,则覆盖去重,若不等,则使用其他算法进行二次寻址
会调用eq判断两个元素值是否相等(==),若值相等,则覆盖去重,若不等,则使用其他算法进行二次寻址
站在上帝的角度去考虑
0 条评论
下一页