面向对象基础总结
继承
什么是继承?
继承是一种新建类的方式 新建类称为 子类 /派生类 被继承的类称之为 父类/基类/超类
继承的 特性: 子类可以遗传/重用父类的属性
1.python中一个子类可以同时继承多个父类
2.在继承背景下说 python中的类分为 两种,新式类,经典类
新式类:但凡继承了object的类 以及该类的子类 都是 新式类(可以用到 object的方法)在python中一个类即便是没有显示的继承任何类 默认就会继承object
经典类:没有继承object的类,以及该类的子类 .. 都是经典类 python2 中才会区分新式类和经典类 在python中一个类即便是没有显示的继承任何类 也不会继承object
class Foo(object): python3和python2 中都可以用的新式类
pass
print(Foo.__bases__) # 查看基类符 父类
为何要是用继承?
减少类与类之间的代码冗余
class Foo(object):
x = 111
class Sub(Foo):
x = 222
f = Sub()
f.x = 333
print(f.x)
在子类派生的新方法中重用父类功能的方式一
指名道姓的方式: 指名道姓的引用某一个;类的函数
# 总结 和继承没有关系 2.访问的是类的函数 没有自动传值得效果
class Oldboy:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
class Student(Oldboy):
def __init__(self,name, age, sex, score):
Oldboy.__init__(self,name, age, sex)
self.score = score
菱形继承问题:
新式类:广度优先,从左往右一个分支一个分支的查找,最后一个分支才去顶级查找
经典类:深度优先查找,从左往右有个分支一个分支的查找,在第一个分支就去顶级查找
f.mto() #等于f.__mro__ 查看顺序 mro列表就是一个简单的所有基类的线性顺序
class A:
pass
class B(A):
pass
class C(B):
pass
print(C.mro())
# [<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
在子类派生的新方法中重用父类功能的方式二super
super(自己的类名,自己的 对象)必须在类中使用
#在python2中 :super(自己的类名,自己的对象)
#在python3中 :super()
#调用该函数会得到一个返回值 是一个特殊的对象 对象访问一个功能 就是绑定方法 自动传值 该对象专门用来父类中的属性!!!
完全参照mro列表查找 严格依赖继承 mro列表 访问的是一个绑定方法 有自动传值的方法
class Oldboy:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
class Student(Oldboy):
def __init__(self,name, age, sex, score):
Oldboy.__init__(self,name, age, sex)
super(Oldboy,self).__init__(name, age, sex)
super().__init__(name, age, sex)
self.score = score
组合
组合指的是某一个对象拥有一个属性,这个属性是另外一个类的对象
多态
什么是多态?
同一种事物分不同的形态
class Animal: #动物有了就全都有了
def speak(self):
pass
class dog(Animal):
pass
class pig(Animal):
pass
class people(Animal):
pass
obj = dog()
obj1 = pig()
obj2 = people()
obj.speak()
obj1.speak()
obj2.speak()
为什么使用多态
多态性:在多态的背景下,可以不用考虑对象具体类型的前提下而直接使用对象
模块abc 强制子类遵循父类的规范
import abc
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def speak(self):
pass
class People(Animal):
def speak(self):
print('say helllo')
class pig(Animal):
def speak(self):
print('henehnehen')
class dog(Animal):
def speak(self):
print('wannwanwna')
obj = People()
obj2 = pig()
obj3 = dog()
python中 不推崇限制你 崇尚鸭子类型 只要你长得像 你就是
封装
什么是封装? 装 :往名称空间里/容器里存入名字
封: 代表 将存放于名称空间的名字隐藏起来 对外 不对内
如何装?
在类定的属性前加__开头 没有结尾 (****)
class A:
__x = 123
def __init__(self, name, age):
self.__name = name
self.__age = age
def get__(self): #通过函数是可以访问的
print(self.__name, self.__age)
# 对外隐藏 内部是可以访问到的
#__ 到底如何实现了隐藏
只要是__开头的 他就会把你的开头改成 _A__X : 123 仅仅只是语法意义上的变形 并不会真正的限制类外部的访问
#如何实现的对外隐藏 对内开放
改变形操作 只会在类定义阶段 检测语法时 执行一次,类定义阶段之后新增的__开头的属性并不会变形
为什么要封装?
封数据属性 : 将数据属性隐藏起来 类外部无法直接操作属性 需要类内部开辟一个接口 可以使外部间接的操作属性 (可以在接口上定义任意的控制逻辑 从而严格的控制属性)
封函数属性 :隔离复杂度 还是不能直接给外部使用 需要开个接口来调用
property装饰器 是用来将类中的函数属性装饰成数据属性
class D:
def __init__(self, name, height, weight):
self.__name = name
self.height = height
self.weight = weight
@property
def bim(self):
return self.weight / (self.height**2)
@bin.setter
def bin(self,obj)
if type(obj) is not str:
print('输入字符串呀')
self.__name == obj
@bin.deleter
def bin(self)
del self.__name
s = D()
s.bim #就可以调用了
s.bim = 'engon'
del s.bin
bin = property(get_bin, set_bin, del_bin)
绑定方法 与 非绑定方法
两大类 三小种
绑定方法 绑定给谁 就会把谁当做第一个参数传入
绑定给对象的 类中定义的函数都是绑定给对象的
classmethod 会将类作为第一个参数自动传入 (需要类名或其他 )
staticmethod 非绑定方法 既不与类绑定 又不与对象绑定 普通函数没有自动传值的效果
class A:
def index(self):
print('我是对象绑定')
@classmethod
def f2 (cls):
print('我是绑定给类的')
import uuid
uuid.uuid4() 生成一个第一无二的编号
面向对象高级(边边脚脚)
isinstance () 判断一个对象是否是一个类的实例 返回true false
print(isinstance([1,23,4], list))
issubclass() 判断是否是子类 (父类, 子类)
反射 属性操作 通过字符串 反射或者映射到对象或者类的属性上
hasarrt 本质 'name' in obj.__dict __判断有没有
getattr 本质 obj.dict['name'] 获取属性的值 没有报错 第三个参数有的话找不到返回
setattr 设置值 修改值 setattr(obj,'name', 'egon') 存在修改 不存在 添加
delattr delattr(obj, 'name') 删除
内置方法 str del
# 内置方法是 满足某种条件下自动触发
__str__ 在对象被打印时自动触发,可以用来定义对象被打印时的输出信息
__del__ 在对象被删除时先自动触发 可以用来回收对象以外的其他相关资源
__call__ (self, *args, **kwargs) 在对象被调用时先自动触发 可以用来回收对象以外的其他相关资源