面向对象
目录
#面向对象
面向过程
#python中的两大范式:1 面向过程,2 面向对象
面向过程:====》做一件事情的先后顺序
面向过程的优点:===》把问题简单化
面向过程的优点:===》扩展性差
面向对象的概念
#在python中,只需要知道一切皆对象
1 在程序中:
对象就是盛放"数据属性(变量)"和"功能(函数)"的容器
2 生活中
对象就是"特征"和"技能(功能)"的结合体
类的定义和对象的产生
#对象:一系列"特征"与"功能"的结合体
#类:一系列"相似特征"与"相似功能"的结合体
#在程序中
先定义类,然后再调用类产生对象
语法格式
class 类名():
pass
函数的定义语法格式
def 函数名():
pass
"""
定义类发生的几件事情?
1. 定义类,会立马执行类体代码
2. 产生类的名称空间,并且把类中的属性和方法名字丢在类的名称空间中,其实就是丢在大字典里
3. 把类的名称空间绑定给__dict__,类名.__dict__
"""
'''调用类产生对象,得到的额对象就是一个空对象,空字典'''
定制对象独有的属性
初始化方法,当类被加括号调用的时候,会自带触发这个函数执行
'''初始化方法,第一个参数是类产生的对象,这个不用传入,
在这里不能直接使用对象点类中的属性'''
属性的查找顺序
1 类属性查找顺序
增加属性
修改属性====》eg:School.name="jhc" #如果这个name在School中不存在,则增加这个类
#如果存在,则修改这个类对应的值
删除属性=====》eg:del School.name #如果这个类中不存在这个属性,会报错
2 对象属性查找顺序
查看属性======》eg:Index.name #如果对象中不存在这个属性,再去产生这个对象的类中去查找,如果找不到,则会报错
增加属性
修改属性=====》eg:Index.name #如果这个name在Index中不存在,则增加这个对象类
#如果存在,则修改这个类对应的值
删除属性=======》eg:del Index.money #如果这个对象属性中存在这个属性,则可以删除成功,反之,
绑定方法
-
绑定给对象的方法
class Index(): School="jhc" #自定义方法 def __init__(self,name,age): self.name=name self.age=age #功能 def tell_info(self,username,password): print(self.name,self.age,username,password) stu=Index("lyx",19)#调用类产生对象 stu.tell_info("syd",123) #绑定对象stu,对象来调用 #绑定给对象的方法由对象来调用,特殊之处在于,对象在调用时会将自己作为第一个参数传递给形参
-
绑定给类的方法(@classmethod)
class Index(): School="jhc" #自定义方法 def __init__(self,name,age): self.name=name self.age=age #功能 @classmethod def tell_info(cls,username,password): print(cls) print(username,password,Index.School) stu=Index("lyx",19) Index.tell_info("syd",123) '''绑定给类的方法,类来调用,特殊之处在于:把类名当成第一个参数传给方法的第一个形参'''
非绑定方法(@staticmethod)
'''如果不需要用到对象,和类,可以不绑定这两种方法'''
隐藏属性
1 如何隐藏 '''1 在类定义阶段,隐藏属性发生了变形:_类名__属性名 2 隐藏属性既可以隐藏类属性,类方法,对象属性都可以隐藏 3 隐藏对外不对内 ''' 2 为什么要隐藏 '''由于隐藏是对外不对内,只需要开放一个接口,来返回内部被隐藏的 属性值,可以更好的对外限制''' 3 用法 '''使用__名'''
property装饰器
@property(属性) #把方法伪装成属性来使用 class Index(): __county="arget" @property #伪装属性为county def county(self): return Index.__county @county.setter #修改这个属性值 def county(self,v): if not type(v) ==str: print("不能修改哦") Index.__county= v @county.deleter #删除 def county(self): del Index.__county stu=Index() print(stu.county) #查看隐藏属性 #修改属性 stu.county="meet" print(stu.county) #删除属性 del stu.county print(stu.county) 方法二 class Index(): __county="arget" # @property #伪装属性为county def get_county(self): return Index.__county # @county.setter #修改这个属性值 def set_county(self,v): if not type(v) ==str: print("不能修改哦") Index.__county= v # @county.deleter #删除 def del_county(self): del Index.__county ret=property(Index.get_county,Index.set_county,Index.del_county)
面向对象的三大特征
1 封装 #将零散的功能归纳 2 继承 1 什么是继承 继承就是新建类的一种方法,新建出来的类被称为子类或者派生类 被继承的类称为父类或者基类 2 为什么要继承 类:解决了对象与对象之间的代码冗余问题 继承:解决了类与类之间的代码冗余问题 3 怎么使用继承 经典类:没有继承object类 新式类:继承了objectl类 3 多态 多态从代码的角度理解的话,就是子类的方法覆盖了基类的同名方法,即重定义;从实际场景理解的话, 就是同一种说法有着不同的用途。 为方便理解,假设这么一个场景:一个父亲有两个孩子,但这三个人都会挣钱, 但挣的钱不一样多,那么该如何去实现这种功能呢? 首先看类的定义: class Father(): # 基类的定义 def earn_money(self): return 15000 # 挣15000 class Son1(Father): # 第一个子类的定义 def earn_money(self): return 7000 # 挣7000 class Son2(Father): # 第二个子类的定义 def earn_money(self): return 6000 # 挣6000 接着看结果: # 首先分别实例化三个类 dashuai = Father() xiaoming = Son1() xiaohua = Son2() # 打印相应的结果 print(dashuai.earn_money()) # 返回15000 print(xiaoming.earn_money()) # 返回7000 print(xiaohua.earn_money()) # 返回6000 很显然,由于三个人都会挣钱,所以在代码中的体现是都有earn_money这个方法的。 但是,三个类的对象调用的方法返回了三个不同的值,很显然子类的方法“重写”了基类的方法, 多态这个特性也因此得以体现。 显而易见的是,多态使得代码更为灵活,因为子类可以覆盖基类的方法;当然,也使得代码容易拓展。
继承
1 单继承下的属性查找
#单继承:只继承一个类
eg:
class INdex():
pass
class ward(INdex):
pass
单继承下的属性查找顺序
#先从对象自己的名称空间中查找,找不到再从产生这个类的对象中查找
#类中找不到再去继承的基类中查找,一直找到没有基类为止
#再找不到就报错
2 多继承下的属性查找
多继承可以说成菱形查找,被继承的多个类最终都汇聚到一个点上
1 经典类
#查找顺序====》是按照深度优先===》刚刚开始就会找到最后那个
2 新式类
#查找顺序====》是按照广度优先===》最后一个找object类
super关键字
#我们在子类中需要调用父类的方法时才会这么用。可以使用mro查看类的继承
#简单记就是,按照继承顺序去查找,找不到,则报错
#用法 super().xxx
描述
super() 函数是用于调用父类(超类)的一个方法。
super() 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,
但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。
语法
以下是 super() 方法的语法:
super(type[, object-or-type])
参数
type -- 类。
object-or-type -- 类,一般是 self
Python3.x 和 Python2.x 的一个区别是:
Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx :
多态与多态性(鸭子类型)
多态理解:一种事物的多种形态
eg 水:液态,气态,固态
动物:人,狗,猪
写一个多态(将基类格式化,衍生类必须按照基类的格式)
import abc #abstract class 抽象类
抽象类的特点:只能被继承,不能被实例化哈
class student(metaclass=abc.ABCMeta): #metaclass=abc.ABCMeta 抽象化这个类
@abc.abstractmethod
def cource():#抽象方法
pass
'''注意,基类中不实现具体的方法,只是规范衍生类中的方法'''
多态性==》鸭子类型
再程序中没有做出明确的限制,但每一个方法都按照了假继承的规范来书写
eg:class Index():
def name():
pass
class login():
def name():
pass
'''多态性带来的特性,在不考虑对象的类型下,直接调用对象的对应方法'''
多态性
def len(obj):
return obj.__len__()
len("abjd")
len([1,2,3,4,5])
len({"a":1})
鸭子类型:它是一种动态的编程风格,我们更关注的是对象的行为,而不是对象的类型
我们不用在使用type和isinstance查出它的类型了
允许我们在调用方法的时候,只要对象拥有这个方法,我们就可以当成参数传递过去,而不关心类型
组合
#组合:一个对象拥有一个属性,但这个属性的值是另外一个对象
#继承===》满足什么是什么的关系
#组合===》满足什么有什么的关系 简单记就是,某一个人或者自己有什么自己想要的东西或者别人想要的东西
eg:class Index():
pass
class Home():
pass
stu=Index()
stu2=Home()
stu.x =stu2
面向对象之魔法方法
'''魔法方法只需要记住各个魔法方法的触发条件'''
1 __init__ #初始化方法,调用类的时候自带触发,里面有一个self参数,用来接收对象
2 __str__ #打印或者输出的时候,会自动触发 '''注意,返回值必须是字符串类型'''
3 __repr__ #打印或者输出的时候,会自动触发 '''注意,返回值必须是字符串类型'''
'''当__str__和__repr__同时存在时,__str__的优先级最高,即只执行__str__'''
4 __del__ #当删除对象的时候会自动触发的方法
# 当程序全部执行完毕,也会自动调用触发
5 __doc__ #输出多行注释的内容
6 __enter__,__exit__
'''__enter__(): 在使用with语句时调用,会话管理器在代码块开始前调用,返回值与as后的参数绑定
__exit__(): 会话管理器在代码块执行完成好后调用,在with语句完成时,对象销毁之前调用'''
'''class Open:
def __init__(self, name):
self.name = name
def __enter__(self): #先
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
def __exit__(self, exc_type, exc_val, exc_tb):#后
print('with中代码块执行完毕时执行我啊')
print(exc_type)
print(exc_val)
print(exc_tb)
return True
with Open('a.txt') as f:
print('=====>执行代码块')
raise TypeError('***着火啦,救火啊***') # 它是主动抛出异常
print('0' * 100) # ------------------------------->不会执行
'''
7 __setattr__,__delattr__,__getattr__(修改,删除,获取)
1 当查找属性不存在时,执行__getattr__
2 当修改属性的时候会执行__setattr__ 注意
''' self.__dict__[key] = value
# self.key=value #这就无限递归了,你好好想想
# self.__dict__[key]=value #应该使用它'''
这一个地方要注意,需要去这个对象的名称空间去修改这个属性的值,否则会出现无限递归
,原因是,你给的这个值他只是完成了传递给key,value,并没有修改到名称空间
3 当你执行删除的时候,会执行__delattr__,
''' # # del self.item #无限递归了
# self.__dict__.pop(item)'''
'''理解成需要在这个对象的名称空间去修改,或者删除,否则会出现无限递归'''
'''attr方法使用的是点语法'''
7 __setitem__,__getitem__,__delitem__(修改,获取,删除)
'''同样也是在对象的名称空间去修改,删除,查看'''
1 当对象通过中括号取值的时候会自动触发__getitem__
2 当对象中括号修改值的时候,会自动触发__setitem__,并且,key就是括号中的key,value就是=右边的值
3 当执行删除的时候会触发__delitem__,'''self.__dict__.pop(item)'''
8 __call__
'''对象加括号的时候就会自动触发'''
'''flask框架源码的时候,__call__方法就是入口'''
反射
在python中,反射指的是"通过字符串来操作对象的属性"
涉及到四个内置函数的使用
1 getattr() #获取
2 setattr() #修改
3 delattr() #删除
4 hasattr() #是否存在这个属性
1 getattr()
getattr(stu,"name")
#当获取的时候属性不存在,会报错,可以通过传入第三个来避免报错
# 如果是方法名,得到的结果就是函数的内存地址,要想执行,就要结果加括号
2 setattr()
setattr(stu,"name","123")
#给对象添加属性,如果属性不存在,增加属性
#给对象增加属性,如果属性存在,则修改属性值
3 delattr()
delattr(stu,"name")
#删除属性
4 hasattr()
hasattr(stu,"name")
#判断属性是否存在
补充
importrandom
random=__import__("random")
res=random.eandint(1,6)
print(res)
反射案例
class FtpServer:
def serve_forever(self):
while True:
inp = input('input your cmd>>: ').strip() # get a.txt
cmd, file = inp.split() # get a.txt
if hasattr(self, cmd): # 根据用户输入的cmd,判断对象self有无对应的方法属性
func = getattr(self, cmd) # 根据字符串cmd,获取对象self对应的方法属性
func(file)
def get(self, file):
print('Downloading %s...' % file)
def put(self, file):
print('Uploading %s...' % file)
server = FtpServer()
server.serve_forever()
异常
1 什么是异常:错误发生的信号,如果不处理这些错误,接下来的代码将不会在执行
2 处理异常的完整语法结构
try:
pass
except 类型:
pass
else:
pass
finally:
pass
3 主动抛出异常
'''使用raise Exception("data")'''
class Animal():
def speak(self):
raise Exception('必须实现speak方法')
class People(Animal):
def speak(self):
pass
obj=People()
obj.speak()
4 断言
assert
'''# d = {'username1':'kevin', 'age':20}
# assert 'username' in d
# print('21134243')
'''
'''可以作为条件判断'''