Title

面向对象

#面向对象

面向过程

#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')
'''

'''可以作为条件判断'''
posted @ 2023-03-16 15:44  哈哈哈哼  阅读(24)  评论(0编辑  收藏  举报