面向对象

自闭症网瘾萝莉.ら 提交于 2020-01-26 18:18:38

第六章 面向对象

规范化目录

  • 规范化目录的优点

    #1:加载速度块#2:可读性高#3:查询修改代码时都简单​
  • 规范化目录分析

    • 划归固定的路径

      将文件目录的固定路径划分完成​
    • settings.py配置文件

      #1:基本存储的都是变量#2:静态路径,数据库的链接,配置,静态文件的的路径,基本不发生改变的​
    • src.py主逻辑函数

      #主逻辑函数,核心函数:贯穿整个项目的主要功能​
    • common.py公共组件

      #放置一些公用的函数,功能,方便与其他的函数或者业务需求,如:装饰器​
    • start启动文件

      #单独的启动文件,将所有项目的功能单独放置一个文件中,开启项目方便,醒目​
    • register

      #用户信息,数据相关,多个文件​
    • logging日志文件

      #记录用户的访问次数,转账,取钱,充钱等等.极了用户干了什么.​
    • README描述文件

      #1:软件定位,软件的基本功能。#2:运行代码的方法: 安装环境、启动命令等。#3:简要的使用说明。#4:代码目录结构说明,更详细点可以说明软件的基本原理。#5:常见问题说明。​
  • 规范化目录sys模块路径加载

    #版本一sys模块内置模块,文件运行时,sys内置模块就会将一些模块 自动  加载到内存. 内置模块. time,json pickle等等.以及当前目录的.如何引用到一个模块最本质的原因在于这个模块名称空间在不在内存.如果直接引用不到一个模块,他必定不是内置或者当前目录下的py文件.所以,我们要手动将其添加到内存. sys.path.append()就是手动的将一些模块添加到内存,添加完毕之后,就可以直接引用了.#================================================import sys#版本二: 繁琐,我要将整个项目作为根目录,添加到内存中.sys.path.append(r'F:\s24\day20\模拟博客园代码\blog\core')sys.path.append(r'F:\s24\day20\模拟博客园代码\blog\conf')sys.path.append(r'F:\s24\day20\模拟博客园代码\blog\db')from src import runrun()#================================================#版本三: 你把项目路径写死了,所有的开发人员如果共同开发这个项目,必须都得按照这#个目录结构去构建.import syssys.path.append(r'F:\s24\day20\模拟博客园代码\blog')from core.src import runrun()#================================================# 版本四:import sysimport os​# print(__file__)# print(os.path.dirname(os.path.dirname(__file__)))# sys.path.append(r'F:\s24\day20\模拟博客园代码\blog')# from core.src import run# run()​BASE_PATH = os.path.dirname(os.path.dirname(__file__))sys.path.append(BASE_PATH)from core.src import runif __name__ == '__main__':    run()目录结构:    blog        bin(starts),conf(settings),core(src),db,lib(common),log

面向对象编程的优势

#易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护​

面向对象初识

'''想要学习面向对象必须站在一个上帝的角度去分析考虑问题.    类: 具有相同属性和功能的一类事物.    对象:某个类的具体体现.​汽车: 汽车类, 楼下停着一个车牌号为9nb11的奥迪对象.猫科类: 类. 陈硕家的养的那个大橘.对象.鸡类: 一个类. 家里养的一只鸡.男神:是一类. 太白对象.​面向对象的第二优点: 你要站在上帝的角度构建代码,类就是一个公共的模板,对象就是从模板实例化出来的.得到对象就得到了一切.'''​

面向对象的结构

class Human:    """    类的具体结构    """    # 第一部分:静态属性    mind = '有思想'   # 类的属性  (静态属性, 静态字段)    language = '使用语言'​    # 第二部分: 动态方法    def work(self):        print('人类都会工作')​    def eat(self):        print('人类都需要吃饭')​

从类名的角度研究类

# class Human:#     """#     类的具体结构#     """#     # 第一部分:静态属性#     mind = '有思想'   # 类的属性  (静态属性, 静态字段)#     language = '使用语言'##     # 第二部分: 动态方法#     def work(self):#         print('人类都会工作')##     def eat(self):#         print('人类都需要吃饭')​# 1. 类名操作类中的属性#     1. 类名查看类中所有的内容# print(Human.__dict__)#     2. 类名操作类中的静态属性  万能的点.​# 增:# Human.body = '有头和四肢'# 删:# del Human.mind# 改:# Human.mind = 'liye脑残'# 查:# print(Human.language)# print(Human.__dict__)​# 2. 类名调用类中的方法(一般类中的(静态方法,类方法)方法不会通过类名调用)# Human.work(111)​# 总结:# 一般类名就是操作类中的属性.​

从对象角度研究类

# class Human:#     """#     类的具体结构#     """#     # 第一部分:静态属性#     mind = '有思想'   # 类的属性  (静态属性, 静态字段)#     language = '使用语言'##     def __init__(self):#         # print(f'self---->: {self}')#         # print(666)#         self.name = '李业'#         self.age = 18##     # 第二部分: 动态方法#     def work(self):#         print('人类都会工作')##     def eat(self):#         print('人类都需要吃饭')## obj = Human()  # 实例化过程# 得到一个返回值,这个返回值就是 对象,实例.# print(f'obj---> {obj}')=================# 实例化一个对象发生了三件事(重点++++):'''    1. 触发__new__方法 ,开辟一个对象空间.    2. 自动执行__init__方法,并且将对象地址传给self.    3. 运行__init__方法内的代码,给对象空间封装属性.(完整版)​'''​​​class Human:    """    类的具体结构    """    # 第一部分:静态属性    mind = '有思想'   # 类的属性  (静态属性, 静态字段)    language = '使用语言'​    def __init__(self, name, age):        # print(f'self---->: {self}')        # print(666)        self.n = name        self.a = age​​    # 第二部分: 动态方法    def work(self):        # print(f'self---> {self}')        print(f'{self.n}都会工作')​​    def eat(self):        print(f'{self.n}都需要吃饭')​# obj = Human('李业',18)  # 实例化过程# print(obj.n)# print(obj.a)# print(obj.__dict__)​# 一:对象操作对象空间的属性​# 1. 对象查看对象的空间的所有属性# obj = Human('李业',18)# print(obj.__dict__)​# 2. 对象操作对象空间的属性# obj = Human('李业',18)# 增:# obj.sex = 'laddy_boy'# 删:# del obj.a# 改:# obj.a = 1000# 查:# print(obj.n)# print(obj.__dict__)​# 二 对象查看类中的属性# obj = Human('李业',18)# # print(obj.mind)# obj.mind = '无脑的'# print(obj.mind)# print(Human.mind)​# 三 对象调用类中的方法# obj = Human('孙戴维', 23)# # print(f'obj---> {obj}')# obj.work()# obj.eat()​# 一个类可以实例化多个对象# obj1 = Human('李业',18)# obj2 = Human('小可爱', 16)# obj3 = Human('怼姐', 18)​# 变量,函数名:# age_of_oldboy = 73# Ageofoldboy​

从空间角度研究类

对象空间与类空间有相同的名字, 对象. 肯定先从对象空间查找.查询顺序:•   对象.名字: 对象空间 类对象指针_--> 类空间 ---> 父类空间•   类名.名字: 类空间 -----> 父类空间​

 

类与类之间的关系

  • 依赖关系

    # 依赖关系: 将一个类的类名或者对象传入另一个类的方法中​# #1. 依赖关系: 主从之分.# class Elephant:#     def __init__(self,name):#         self.name = name#     def open(self,obj):#         print(f'{self.name} 默念三声: 3,2,1 开门')#         obj.be_open()#     def close(self):#         print(f'{self.name} 默念三声: 3,2,1 关门')## class Refrigerator:#     def __init__(self, name):#         self.name = name#     def be_open(self):#         print(f'{self.name}冰箱 被打开了')#     def be_close(self):#         print(f'{self.name}冰箱 被关闭了')​
  • 组合关系

    #给一个类的对象封装一个属性,此属性为另一个类的对象#class Boy:#     def __init__(self,name,age,girlfriend=None):#         self.name=name#         self.age=age#         self.girlfriend=girlfriend#     def eat(self):#         if self.girlfriend:#             print(f'{self.name}和{self.girlfriend.name}')#         else:#             print('吃个屁')# class Girl:#     def __init__(self,name,age):#         self.name=name#         self.age=age# p=Boy('李业',30)# g=Girl('如花',56)# p.girlfriend=g# p.eat()​

     

 

继承

  • 初识继承

    #字面意思: 儿子可以完全使用父亲的所有内容#专业角度: 如果B类继承A类,#   B类就称为子类,派生类.#   A类就称为父类,基类,超类.#面向对象三大特性之一:继承,封装,多态.#继承: 单继承,多继承.​
  • 继承的优点

    #减少重复代码.#增加类之间的耦合性.#代码更加清晰,流畅.​
  • 单继承

    #类名执行父类属性方法#对象执行父类属性方法#在子类中既执行字类方法又执行父类方法​
  • 多继承

    #python 类分为两种:#python2x :#•  python2.2之前,都是经典类.python2.2之后,经典类与新式类共存.#python3x:#•  全部都是新式类.#经典类: 不继承object类, 深度优先原则.#新式类:继承object类. mro(C3)算法#经典类的深度优先#新式类的mro算法===============================================#如果想执行父类的func方法,这个方法并且子类中夜用,那么就在子类的方法中写上:#1:父类.func(对象,其他参数)#2:利用super,super().func(参数)​
  • super的用法(重点++++)

    1:super 可以重构父类的方法2:在新式类的多继承中,super严格按照 self 对象从属于类的mro顺序进行查找,默认执行本类 的下一个类(简单的记就是:跳过本类,按照Mro算法的执行顺序,执行下一类的操作)​

     

  • mro(C3)算法

    mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )(其中Child继承自Base1, Base2)​
    如计算merge( [E,O], [C,E,F,O], [C] )有三个列表 :  ①      ②          ③​1 merge不为空,取出第一个列表列表①的表头E,进行判断                                 各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表2 取出列表②的表头C,进行判断   C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除   merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )3 进行下一次新的merge操作 ......​
    mro(A) = mro( A(B,C) )​原式= [A] + merge( mro(B),mro(C),[B,C] )​  mro(B) = mro( B(D,E) )         = [B] + merge( mro(D), mro(E), [D,E] )  # 多继承         = [B] + merge( [D,O] , [E,O] , [D,E] )  # 单继承mro(D(O))=[D,O]         = [B,D] + merge( [O] , [E,O]  ,  [E] )  # 拿出并删除D         = [B,D,E] + merge([O] ,  [O])         = [B,D,E,O]​  mro(C) = mro( C(E,F) )         = [C] + merge( mro(E), mro(F), [E,F] )         = [C] + merge( [E,O] , [F,O] , [E,F] )         = [C,E] + merge( [O] , [F,O]  ,  [F] )  # 跳过O,拿出并删除         = [C,E,F] + merge([O] ,  [O])         = [C,E,F,O]​原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])    = [A,B] + merge( [D,E,O], [C,E,F,O],   [C])    = [A,B,D] + merge( [E,O], [C,E,F,O],   [C])  # 跳过E    = [A,B,D,C] + merge([E,O],  [E,F,O])    = [A,B,D,C,E] + merge([O],    [F,O])  # 跳过O    = [A,B,D,C,E,F] + merge([O],    [O])    = [A,B,D,C,E,F,O]​
  • 简述面向对象的新式类与经典类

    #经典类在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.经典类采用深度优先遍历方案#新式类在python2.2之后出现了新式类. 新式类的特点是基类的根是object类,python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object,新式类采用C3算法遍历原则,MRO序列​

     

面向对象的三大特性

  • 封装

    #对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过对象直接或者self间接获取被封装的内容把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分析. 比如. 你写了⼀个很⽜B的函数. 那这个也可以被称为封装. 在⾯向对象思想中. 是把⼀些看似⽆关紧要的内容组合到⼀起统⼀进⾏存储和使⽤. 这就是封装.​
  • 继承

    #⼦类可以⾃动拥有⽗类中除了私有属性外的其他所有内容. 说⽩了, ⼉⼦可以随便⽤爹的东⻄. 但是朋友们, ⼀定要认清楚⼀个事情. 必须先有爹, 后有⼉⼦. 顺序不能乱, 在python中实现继承非常简单. 在声明类的时候, 在类名后⾯添加⼀个⼩括号,就可以完成继承关系. 那么什么情况可以使⽤继承呢? 单纯的从代码层⾯上来看. 两个类具有相同的功能或者特征的时候. 可以采⽤继承的形式. 提取⼀个⽗类, 这个⽗类中编写着两个类相同的部分. 然后两个类分别取继承这个类就可以了. 这样写的好处是我们可以避免写很多重复的功能和代码. 如果从语义中去分析的话. 会简单很多. 如果语境中出现了x是⼀种y. 这时, y是⼀种泛化的概念. x比y更加具体. 那这时x就是y的⼦类. 比如. 猫是⼀种动物. 猫继承动物. 动物能动. 猫也能动. 这时猫在创建的时候就有了动物的"动"这个属性. 再比如, ⽩骨精是⼀个妖怪. 妖怪天⽣就有⼀个比较不好的功能叫"吃⼈", ⽩骨精⼀出⽣就知道如何"吃⼈". 此时 ⽩骨精继承妖精.​
  • 多态

    #多态,同一个对象,多种形态。python默认支持多态。​
  • 三大特性总结

    #继承:单继承和多继承,子承父业如果B继承A,那A称作父类,基类,B称作子类,派生类B继承A,那么B就可以拥有A所有的属性和方法,一个类可以多个父类​#多态多种形态,Python中有很多地方都体现了多态,例如:定义一个变量a,a=2,这时a是个整型我也可以再给a赋值,a = '你好',这时的a就是一个字符串类型,一个变量有多种形态,体现的就是多态​#封装python中的函数 模块 类 都属于封装,把固定功能的代码封装到一个代码块中,就属于封装​

     

类的约束

  • 约束的概念

    #约束. 其实就是⽗类对⼦类进⾏约束. ⼦类必须要写xxx⽅法. 在python中约束的⽅式和⽅法有两种:#1. 使⽤抽象类和抽象⽅法, 由于该⽅案来源是java和c#. 所以使⽤频率还是很少的#2. 使⽤⼈为抛出异常的⽅案. 并且尽量抛出的是NotImplementError. 这样比较专业, ⽽且错误比较明确.(推荐)​
  • 约束的两种方式

    #第一种class Payment:    """    此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。    """    def pay(self,money):        raise Exception("你没有实现pay方法")​class QQpay(Payment):    def pay(self,money):        print('使用qq支付%s元' % money)​class Alipay(Payment):    def pay(self,money):        print('使用阿里支付%s元' % money)​class Wechatpay(Payment):    def fuqian(self,money):        print('使用微信支付%s元' % money)​​def pay(obj,money):    obj.pay(money)​a = Alipay()b = QQpay()c = Wechatpay()pay(a,100)pay(b,200)pay(c,300)#========================================================#第二种from abc import ABCMeta,abstractmethodclass Payment(metaclass=ABCMeta):    # 抽象类 接口类  规范和约束  metaclass指定的是一个元类    @abstractmethod    def pay(self):pass  # 抽象方法​class Alipay(Payment):    def pay(self,money):        print('使用支付宝支付了%s元'%money)​class QQpay(Payment):    def pay(self,money):        print('使用qq支付了%s元'%money)​class Wechatpay(Payment):    # def pay(self,money):    #     print('使用微信支付了%s元'%money)    def recharge(self):pass​def pay(a,money):    a.pay(money)​a = Alipay()a.pay(100)pay(a,100)    # 归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能q = QQpay()q.pay(100)pay(q,100)w = Wechatpay()pay(w,100)   # 到用的时候才会报错​# 抽象类和接口类做的事情 :建立规范# 制定一个类的metaclass是ABCMeta,# 那么这个类就变成了一个抽象类(接口类)# 这个类的主要功能就是建立一个规范​

super()的深入了解

#严格按照mro的执行顺序去执行#super(Foo,self).f2()  # 按照self对象从属于类的mro的顺序,执行Foo类的下一个类.​class A:    def f1(self):        print('in A')​class Foo(A):    def f1(self):        super().f1()        print('in Foo')​class Bar(A):    def f1(self):        print('in Bar')​class Info(Foo,Bar):    def f1(self):        super().f1()        print('in Info f1')​obj = Info()obj.f1()​'''in Barin Fooin Info f1'''print(Info.mro())  # [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]​

鸭子类型

  • 什么是鸭子类型

    #对相同的功能定义了相同的名字,这样方便开发,两种方法互称为鸭子模型,比如:list str tuple 都有index方法,这种就是统一了规范,互为鸭子模型.​

     

#python中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。#对于代码上的解释其实很简答:class A:    def f1(self):        print('in A f1')        def f2(self):        print('in A f2')​class B:    def f1(self):        print('in A f1')        def f2(self):        print('in A f2')        obj = A()obj.f1()obj.f2()​obj2 = B()obj2.f1()obj2.f2()# A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。# 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。​# 这样的例子比比皆是:str  tuple list 都有 index方法,这就是统一了规范。# str bytes 等等 这就是互称为鸭子类型。​

类的私有成员

  • 类的私有属性

    #类的私有属性,只能在类的内部使用,不能在类的外部和派生类中使用class A:    name='李业'    __name='李业'    def func(self):        print(self.name)        print(self.__name)class B(A):    def func(self):        print(self.name)        print(self.__name)p=A()p.func()b=B()b.func()#报错​
  • 私有对象属性

    #私有对象属性,只能在类的内部使用,不能在类的外部或派生类中使用class A:    def __init__(self,name,age):        self.name=name        self.__age=age    def func(self):        print(self.__age)class B(A):    def func():        print(self.__age)p=A()p.func()b=B()b.func()#报错 ​
  • 类的私有方法

    #类的私有方法只能在类的内部使用,不能在类的外部或者派生类中使用class A:    def __init__(self,name,age):        self.name=name        self.__age=age    def __func(self):        print(self.__age)    def  func(self):        self.__func()        class B(A):    def func():        self.__func()        print(self.__age)p=A()p.func()b=B()b.func()#报错 ​
  • 类的私有成员总结

    #私有成员来说: 当你遇到重要的数据,功能,(只允许本类使用的一些方法,数据)设置成私有成员.# python所有的私有成员都是纸老虎,形同虚设.​class A:     name = '李业'     __name = '钢哥'  # 私有类的属性​     def __func(self):         print('in __func')​ print(A.__dict__) print(A._A__name)# 类从加载时,只要遇到类中的私有成员,都会在私有成员前面加上_类名 ​
  • 类方法

    # 类方法class A:    def func(self):        print('实例方法')​    @classmethod    def cls_func(cls):        # print(f'cls---->{cls}')        obj = cls()        print(obj)        print('类方法')​print(A)A.cls_func()obj = A()obj.cls_func()​# 类方法: 一般就是通过类名去调用的方法,并且自动将类名地址传给cls,# 但是如果通过对象调用也可以,但是传的地址还是类名地址.# A.cls_func()​# 类方法有什么用???#     1. 得到类名可以实例化对象.#     2. 可以操作类的属性.​# 简单引用# 创建学生类,只要实例化一个对象,写一个类方法,统计一下具体实例化多少个学生?# class Student:##     count = 0#     def __init__(self,name,id):##         self.name = name#         self.id = id#         Student.addnum()##     @classmethod#     def addnum(cls):#         cls.count = cls.count + 1##     @classmethod#     def getnum(cls):#         return cls.count#​# obj1 = Student('liye', 12343243243)# obj1 = Student('liye', 12343243243)# obj1 = Student('liye', 12343243243)​# print(Student.getnum())​
  • 静态方法

    # 静态方法# class A:##     def func(self):#         print('实例方法')###     @classmethod#     def cls_func(cls):#         pass##     @staticmethod#     def static_func():#         print('静态方法')## # 静态方法是不依赖于对象与类的,其实静态方法就是函数.# 保证代码的规范性,合理的划分.后续维护性高.# def func():#     pass​​import time​class TimeTest(object):​    area = '中国'    def __init__(self, hour, minute, second):        self.hour = hour        self.minute = minute        self.second = second​    def change_time(self):        print(f'你想调整的时间: {self.hour}时{self.minute}分{self.second}秒')​    @staticmethod    def showTime():        return time.strftime("%H:%M:%S", time.localtime())​​def showTime():    return time.strftime("%H:%M:%S", time.localtime())​def time1():    pass​def time2():    pass# t = TimeTest(2, 10, 10)# # t.change_time()# print(TimeTest.showTime())​
  • 属性方法

    # class Bmi:##     def __init__(self,name,height,weight):##         self.name = name#         self.height = height#         self.weight = weight##     def bmi(self):#         return self.weight/self.height**2## obj = Bmi('赵嘎', 1.83, 65)# print(obj.bmi())# 结果虽然实现了,但是逻辑上感觉不合理.bmi应该是类似于name,age,height,等名词,# 但是你把它当做方法使用了.​​# class Bmi:##     def __init__(self,name,height,weight):##         self.name = name#         self.height = height#         self.weight = weight##     @property#     def bmi(self):#         return self.weight/self.height**2## obj = Bmi('赵嘎', 1.83, 65)# print(obj.bmi)# property 将执行一个函数需要函数名()变换成直接函数名.# 将动态方法 伪装 成了一个属性,虽然在代码级别上没有什么提升,但是让你看起来更合理.# obj.bmi# obj.bmi# obj.bmi = 666## del obj.bmi​# property 他是一个组合.​# class Foo:#     @property#     def bmi(self):#         print('get的时候运行我啊')##     @bmi.setter#     def bmi(self,value):#         print(value)#         print('set的时候运行我啊')#         # return 111  # 无法得到返回值##     @bmi.deleter#     def bmi(self):#         print('delete的时候运行我啊')#         # return 111  # 无法得到返回值## obj = Foo()# # obj.bmi# obj.bmi = 666 # 操作命令 这个命令并不是改变bmi的值,而是执行被bmi.setter装饰器装饰的函数# # obj.bmi(666)# del obj.bmi# 应用场景:    # 1, 面试会考一些基本的调用,流程.    # 2, 工作中如果遇到了一些类似于属性的方法名,可以让其伪装成属性.​​# 设置属性的两种方式:    # 1, 利用装饰器设置属性.# class Foo:#     @property#     def bmi(self):#         print('get的时候运行我啊')##     @bmi.setter#     def bmi(self,value):#         print(value)#         print('set的时候运行我啊')#         # return 111  # 无法得到返回值##     @bmi.deleter#     def bmi(self):#         print('delete的时候运行我啊')#         # return 111  # 无法得到返回值​    # 2. 利用实例化对象的方式设置属性.​# class Foo:#     def get_AAA(self):#         print('get的时候运行我啊')##     def set_AAA(self,value):#         print('set的时候运行我啊')##     def delete_AAA(self):#         print('delete的时候运行我啊')##     AAA = property(get_AAA,set_AA,delete_AAA) #内置property三个参数与get,set,delete一一对应​# f1=Foo()# f1.AAA# f1.AAA='aaa'# del f1.AAA​
  • 内置函数isinstance和issubclass

    # isinstance 判断的是对象与类的关系class A:    pass​class B(A):    pass​obj = B()# isinstance(a,b) 判断的是 a是否是b类 或者 b类派生类 实例化的对象.# print(isinstance(obj, B))  # True# print(isinstance(obj, A))  # True​# issubclass 类与类之间的关系class A:    pass​class B(A):    pass​class C(B):    pass# issubclass(a,b) 判断的是 a类是否是b类 或者 b类派生类 的派生类.# issubclass(a,b) 判断的是 a类是否是b类 子孙类.# print(issubclass(B,A))# print(issubclass(C,A))​

Python中如何判断一个对象是否可调用?如果定义一个类,使其对象本身变成可调用对象

# 第一种方法callable,返回True有可能调用失败,但是返回False,那绝对不能调用def func():    print(1)func()print(callable(func))# 第二种方法,判断对象类型是否属于FunctionType,若为True,则可调用from types import FunctionTypeprint(isinstance(func,FunctionType))# 第三种方法,判断对象是否实现__call__方法print(hasattr(func,'__call__'))# 静态方法属于函数,类方法和实例方法分别依赖于类和对象,所以他们是method,其余我们自己定义的都是函数,函数就可调用若想让一个类的实例化对象可调用,可在类中定义__call__方法,即可实现​

 

元类

#python中一切皆对象,类在某种意义上也是一个对象,python中自己定义的类,以及大部分的内置类,都是由type元类(构建类)实例化来的===================================================#type与object的关系object是type类的一个实例  print(type(object))object是type类的父类     print(issubclass(type,object))#class A:#    pass# obj = A()# print(type('abc'))# print(type([1,2,3]))# print(type((22,33)))# # type 获取对象从属于的类# print(type(A))# print(type(str))# print(type(dict))​
  • 说说type元类与object类的区别与联系

    type元类是获取该对象从属于的类,而type类比较特殊,Python原则是:一切皆对象,其实类也可以理解为'对象',而type元类又称作构建类,python中大多数内置的类(包括object)以及自己定义的类,都是由type元类创造实例化得来的。* 而type类与object类之间的关系比较独特:object是type类的实例,而type类是object类的子类,这种关系比较神奇无法使用python的代码表述,因为定义其中一个之前另一个必须存在.​

     

反射

  • 反射的概念

    #反射是程序对自己内部代码的一种自省方式#反射是通过字符串去操作对象的方式​
  • 反射的主要作用

    #反射主要作用与:#   1:实例对象#   2:类#   3:其他模块#   4:本模块=====================================#反射的组合:#   hasattr,getattr,setattr,delattr​
  • 代码演示

    # 实例对象:​ class A:    country = '中国'     def __init__(self,name,age):         self.name = name         self.age = age     def func(self):         print('in A func') obj = A('赵海狗',47)# hasattr print(hasattr(obj,'name')) print(hasattr(obj,'country')) print(hasattr(obj,'func'))​ print(getattr(obj,'name')) print(getattr(obj,'func')) f = getattr(obj,'func') f() print(getattr(obj,'sex',None)) if hasattr(obj,'name'):     getattr(obj,'name')​# setattr,delattr 用的很少 obj.sex = '公' print(obj.sex) setattr(obj,'sex','公') print(obj.__dict__) delattr(obj,'name') print(obj.__dict__)# 从类的角度:​ class A:     country = '中国'     def __init__(self,name,age):         self.name = name         self.age = age​     def func(self):         print(self)         print('in A func') if hasattr(A,'country'):     print(getattr(A,'country')) if hasattr(A,'func'):     obj = A('赵海狗', 26)     getattr(obj,'func')()     getattr(A,'func')(obj)# 从其他模块:import tbjxprint(getattr(tbjx,'name'))getattr(tbjx,'func')()import tbjx# 1. 找到tbjx对象 的C类,实例化一个对象.print(getattr(tbjx,'C'))obj = getattr(tbjx,'C')('123')# 2. 找到tbjx对象 的C类,通过对C类这个对象使用反射取到area.print(getattr(tbjx.C,'area'))# 3. 找到tbjx对象 的C类,实例化一个对象,对对象进行反射取值.obj = getattr(tbjx,'C')('赵海狗')print(obj.name)print(getattr(obj,'name'))#从当前模块研究反射:a = 666def func1():   print('in 本模块这个对象')​​# def func1():#     print('in func1')## def func2():#     print('in func2')## def func3():#     print('in func3')## def func4():#     print('in func4')​# # func1()# # func2()# # func3()# # l1 = [func1,func2,func3,func4,]# import sys# # # print(sys.modules[__name__])# # print(getattr(sys.modules[__name__],'a'))# # getattr(sys.modules[__name__],'func1')()# # getattr(sys.modules[__name__],'func2')()# # getattr(sys.modules[__name__],'func3')()## func_lst = [f'func{i}' for i in range(1,5)]# # print(func_lst)# for func in func_lst:#     getattr(sys.modules[__name__],func)()​​# class User:#     def login(self):#         print('欢迎来到登录页面')##     def register(self):#         print('欢迎来到注册页面')##     def save(self):#         print('欢迎来到存储页面')## choose_dic = {#     1: User.login,#     2: User.register,#     3: User.save,# }## while 1:#     choose = input('请输入序号: \n1: 登录\n2: 注册\n3: 存储').strip()#     obj = User()#     choose_dic[int(choose)](obj)​​# class User:##     user_list = [('login','登录'),('register','注册'),('save', '存储')]##     def login(self):#         print('欢迎来到登录页面')##     def register(self):#         print('欢迎来到注册页面')##     def save(self):#         print('欢迎来到存储页面')### while 1:#     choose = input('请输入序号: \n1: 登录\n2: 注册\n3: 存储\n').strip()  # 1#     obj = User()#     getattr(obj, obj.user_list[int(choose)-1][0])()  # getattr(obj,'login')​
  • 函数与方法的区别

    #函数是显性传参,不依赖于类,对象#方法是隐性传参,依赖于类,对象#之前学的函数都函数类中方法:#1.如果通过类名调用就是函数#2.如果通过实例化对象调用就是方法#类中的静态方法:是函数#类中的类方法:是方法(最终总结)​​# 1. 通过打印函数名的方式区别什么是方法,什么是函数. (了解)# print(func1)# print(A.func)  # 通过类名调用的类中的实例方法叫做函数.# obj = A()# print(obj.func) # 通过对象调用的类中的实例方法叫方法.​# 2 可以借助模块判断是方法还是函数.​# from types import FunctionType# from types import MethodType## def func():#     pass### class A:#     def func(self):#         pass## obj = A()# print(isinstance(func,FunctionType))  # True# print(isinstance(A.func,FunctionType))  # True# print(isinstance(obj.func,FunctionType))  # False# print(isinstance(obj.func,MethodType))  # True# 总结:# python 中一切皆对象, 类在某种意义上也是一个对象,python中自己定义的类,# 以及大部分内置类,都是由type元类(构建类)实例化得来的.# python 中一切皆对象, 函数在某种意义上也是一个对象,函数这个对象是从FunctionType这个类实例化出来的.# python 中一切皆对象, 方法在某种意义上也是一个对象,方法这个对象是从MethodType这个类实例化出来的.=================================================class A:    @classmethod    def func(cls,a):        pass​    @staticmethod    def func1():        pass​# A.func(222)# A.func()# obj = A()# obj.func()​# 总结: 如何判断类中的是方法还是函数.# 函数都是显性传参,方法都是隐性传参.​
    • 双下方法

      # 特殊的双下方法: 原本是开发python这个语言的程序员用的.源码中使用的.# str : 我们不能轻易使用.慎用.# 双下方法: 你不知道你干了什么就触发某个双下方法.​# __len__# class B:##     def __init__(self,name,age):#         self.name = name#         self.age =age##     def __len__(self):#         print(self.__dict__)##         return len(self.__dict__)  # 2## b = B('leye',28)# print(len(b))# dict# print(len({'name': 'leye', 'age': 28}))==================================================================# class A(object):##     pass## obj = A()# print(hash(obj))# str# print(hash('fdsaf'))==========================================================# ***# class A:##     def __init__(self,name,age):#         self.name = name#         self.age =age##     def __str__(self):#         print(666)#         return f'姓名: {self.name} 年龄: {self.age}'## a = A('赵海狗',35)# b = A('李业',56)# c = A('华丽',18)# 打印对象触发__str__方法# print(f'{a.name}  {a.age}')# print(f'{b.name}  {b.age}')# print(f'{c.name}  {c.age}')# print(a)# print(b)# print(c)# 直接str转化也可以触发.# print(str(a))=============================================================# repr# print('我叫%s' % ('alex'))# print('我叫%r' % ('alex'))# print(repr('fdsaf'))​​# class A:##     def __init__(self,name,age):#         self.name = name#         self.age =age##     def __repr__(self):#         print(666)#         return f'姓名: {self.name} 年龄: {self.age}'## a = A('赵海狗',35)# b = A('李业',56)# c = A('华丽',18)# # print(a)# print(repr(a))# class A:##     def __init__(self,name,age):#         self.name = name#         self.age =age##     def __str__(self):#         return '777'###     def __repr__(self):#         return '666'## a = A('赵海狗',35)# b = A('李业',56)# c = A('华丽',18)# # print(a)# print(a)================================================================# __call__方法  ***# 对象() 自动触发对象从属于类(父类)的__call__方法# class Foo:##     def __init__(self):#         pass##     def __call__(self, *args, **kwargs):#         print('__call__')## obj = Foo()# obj()==========================================================# __eq__# class A(object):#     def __init__(self):#         self.a = 1#         self.b = 2##     def __eq__(self,obj):#         # if  self.a == obj.a and self.b == obj.b:#         #     return True#         return True# x = A()# y = A()# print(x == y)# x = 1# y = 2# print(x+y)==================================================================# __del__析构方法​class A:    def __del__(self):        print(666)obj = A()del obj==================================================# __new__ *** new一个对象  构造方法​# class A(object):# #     def __init__(self):# #         self.x = 1#         print('in init function')# #     def __new__(cls, *args, **kwargs):#         print('in new function')#         return object.__new__(A)  # object 342534​# # 对象是object类的__new__方法 产生了一个对象.# a = A()​# 类名()# 1. 先触发 object的__new__方法,此方法在内存中开辟一个对象空间.# 2. 执行__init__方法,给对象封装属性.​# print(a)===========================================================================# python中的设计模式: 单例模式​# 一个类只允许实例化一个对象.# class A:##     pass# obj = A()# print(obj)# obj1 = A()# print(obj1)# obj2 = A()# print(obj2)# 手写单例模式# class A:#     __instance = None##     def __init__(self,name):#         self.name = name##     def __new__(cls,*args,**kwargs):#         if not cls.__instance:#             cls.__instance = object.__new__(cls)#         return cls.__instance### obj = A('alex')# print(obj)# obj1 = A('李业')# print(obj1.name)# print(obj.name)​
      __init__初始化,给对象封装属性__new__构造方法,新生成一个对象__del__析构方法,当对象在内存中被释放时,触发执行__len__计算长度__hash__判断是否可哈希__str__返回内容__repr__原形毕露,返回其原始值__call__对象+()触发执行call方法__eq__同一类的两个实例比较时会触发__item__对对象进行类似字典的操作就会触发该方法__enter__上下文管理,进入时__exit__上下文管理,出来时​

       

    • item系列

      # __item__系列# __getitem__  __setitem__  __delitem__  对对象做类似于字典的(增删改查)触发__item__系列# __delattr__ del obj.属性  就会触发此方法​# class Foo:#     def __init__(self,name):#         self.name=name##     def __getitem__(self, item):#         # print(item)#         # print(666)#         return self.__dict__[item]##     def __setitem__(self, key, value):#         # self.__dict__[key]=value#         print(key)#         print(value)##     def __delitem__(self, key):#         print('del obj[key]时,我执行')##     def __delattr__(self, item):#         super().__delattr__(item)#         print(f'对象的{item}属性已经删除')### f1=Foo('sb')# print(f1['name'])# f1[1] = 2## del f1[1]​# del f1.name# print(f1.name)​# f1['age']=18# f1['age1']=19# del f1.age1# del f1['age']# f1['name']='alex'# print(f1.__dict__)​
    • 上下文管理

      # # 实例化对象的第二种方式: 必须基于 __enter__ 以及 __exit__这个两个方法.# with A('海狗') as obj:#     print(obj.name)​​# class A:##     def __init__(self, text):#         self.text = text##     def __enter__(self):  # 开启上下文管理器对象时触发此方法#         self.text = self.text + '您来啦'  # 第一步#         print(11111)#         return self  # 必须!!!将实例化的对象返回f1##     def __exit__(self, exc_type, exc_val, exc_tb):  # 执行完上下文管理器对象f1时触发此方法#         print(333)  # 第三步#         self.text = self.text + ',这就走啦'## with A('大爷') as f1:#     print(2222)#     print(f1.text)  # 第二步# print(f1.text)  # 第四步​
    • iter把对象编程一个可迭代的对象

      class A:    def __init__(self,name):        self.name=name    def __iter__(self):        for i  in range(10):            yield ib=A('lijie')for i in b:    print(i)​

    异常处理

    • 什么是异常处理

      调试Python程序时,经常会报出一些异常,异常的原因一方面可能是写程序时由于疏忽或者考虑不全造成了错误,这时就需要根据异常找到出错点,进行分析改正;另一方面,有些异常是不可避免的,但我们可以对异常进行捕获处理,防止程序终止.#注意事项:1.异常处理要慎重使用,因为比较耗性能2.异常处理的所包含的代码区域尽量精简,不要把整段代码都写入try,而是针对个别可能会抛异常的位置进行异常处理​
    • 异常处理中fifinally的用途

      在出现异常之前执行,所以,不管怎样都会执行finally 出不出现异常都执行,异常出现前执行fianlly用途:    1关闭文件句柄,关闭数据库链接.    2 函数return之前能够执行finally代码.    3 break之前可以执行finally​
    • 异常处理结构分支

      # 结构1:单分支try:    num = int(input('>>>'))  # 出现ValueError错误之后,直接跳转到except语句.    dic = {'name': '嘉欣'}    print(dic['age'])​    print(111)except ValueError:    print(666)# 结构2: 多分支​try:    num = int(input('>>>'))  # 出现ValueError错误之后,直接跳转到except语句.    dic = {'name': '嘉欣'}    print(dic['age'])    l1 = [1, 2]    print(l1[100])    print(111)except ValueError:    print('输入的有非数字元素')except KeyError:    print('没有此键')except IndexError:    print('没有此下标')print(666)# 结构3: 万能异常: 处理所有pyhton识别的异常.try:    dic = {'name': '嘉欣'}    # print(dic['age'])    l1 = [1, 2]    print(l1[100])    print(111)    for i in 123:        passexcept Exception as e:    print(e)print(666)​# 什么时候用万能? 什么时候用多分支?# 如果你对错误信息不关心,只是想要排除错误让程序继续运行. 用万能异常.# 你对错误信息要进行明确的分流,让你的程序多元化开发.​# 结构4: 多分支+万能异常​def func():    passdef func1():    passdic = {    1: func,    2: func1,}try:    num = int(input('请输入序号'))    dic[num]()except ValueError:    print('请输入数字')except KeyError:    print('请输入范围内的序号')except Exception:    print('程序出现意料之外的错误....')​# 结构5: try else finallytry:    dic = {'name': '嘉欣'}    # print(dic['age'])    l1 = [1, 2]    # print(l1[100])    print(111)except KeyError:    print('没有此键')except IndexError:    print('没有此下标')else:    print('如果没有出现异常则执行这里')finally:    print('finally 666')​# except 必须依赖于try, else必须依赖于except和try# finally只是依赖于try.​# finally : 在异常出现之前,执行finally语句.try:    dic = {'name': '嘉欣'}    print(dic['age'])    l1 = [1, 2]    print(l1[100])except KeyError:    print('没有此键')except IndexError:    print('没有此下标')finally:    print('finally 666')​# finally 用在 关闭数据库连接,文件句柄关闭,数据保存等,用到finally.with open('test1',encoding='utf-8',mode='r+') as f1:    try:        for i in f1:            print(i)        if ....:    finally:​        f1.close()​# 在return结束函数之前,执行finally代码.def func():    try:        print(111)        return 666    finally:        print(222)print(func())​# 结构6: 主动触发异常.raise ValueError('出现了value错误')# 结构7: 断言: 展现出一种强硬的态度.​# assert 条件name = 'alex'n1 = input('请输入:')assert name == n1#只有assert得条件成立才会执行下面得代码print(111)print(222)​# 自定义异常# python中给你提供的错误类型很多,但是不是全部的错误.class LiYeError(BaseException):​    def __init__(self,msg):        self.msg=msg    def __str__(self):        return self.msg​try:    # 三行    raise LiYeError('socket.connent.....')except LiYeError as e:  # e = LiYeError('类型错误')    print(e)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!