• python之面向对象


    第一章 面向对象初识


    面向对象的三大特性是什么? 抽象、继承、多态。

    面向对象第一个优点:*

    对相似功能的函数,同一个业务的函数进行归类,分类,使你的代码更清晰化,更合理化。

    什么是面向对象。

    面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。

    那什么是类?什么是对象?

    类:就是具有相同属性和功能的一类事物。

    对象:就是类的具体表现。对象一定是不一样的

    面向对象的第二个优点:

    面向对象,要拥有上帝的视角看问题,类其实就是一个公共模板(厂房),对象就是从具体的模板实例化出来,得对象,得一切

    1. 面向对象的结构

    class Human:
        """
        类的具体结构
        """
        #第一部分:静态属性
        mind = "思想"
        language ="语言"
    
        #第二部分:动态方法
        def work(self):
            print("工作")
        def eat(self):
            print("吃饭")
    

    class 是关键字与def用法相同,定义一个类。
    Human是此类的类名,类名使用驼峰(CamelCase)命名风格,首字母大写,私有类可用一个下划线开头。
    类的结构从大方向来说就分为两部分:
    静态变量。
    动态方法。

    1. 从类名的角度研究类

    1.类名操作类中的属性

    class Human:
        """
        类的具体结构
        """
        #第一部分:静态属性
        mind = "思想"
        language ="语言"
    
        #第二部分:动态方法
        def work(self):
            print("工作")
        def eat(self):
            print("吃饭")
    

    1.类名查看类中所有的内容

    print(Human.__dict__)
    

    2.类名操作类中的静态属性

    1.增加

    Human.body="有头发"
    print(Human.__dict__)
    

    2.删除

    del Human.mind
    

    3.改

    Human.mind ="个性"
    print(Human.__dict__)
    

    4.查

    print(Human.language)
    # print(Human.__dict__)
    

    2.类名操作动态方法

    除了两个特殊方法:静态方法,类方法之外,一般不会通过类名操作一个类中的方法.

    Human.work(123)
    

    总结:一般类名

    3. 从对象的角度研究类

    1.什么是对象

    对象是从类中出来的,只要是类名加上(),这就是一个实例化过程,这个就会实例化一个对象。**

    实例化一个对象总共发生了三件事:

      1,在内存中开辟了一个对象空间。

      2,自动执行类中的____init____方法,并将这个对象空间(内存地址)传给了__init__方法的第一个位置参数self。

      3,在____init__ _方法中通过self给对象空间添加属性。

    class Human:
        """
        类的具体结构
        """
        
        mind = "思想"
        language ="语言"
    
        def __init__(self,name,age):
    # self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。
            self.n=name
            self.a=age
        def work(self):
            print("工作")
        def eat(self):
            print("吃饭")
    
    obj=Human("zbb",18) #实例化过程
    #得到一个返回值,这个返回值就是对象,实例
    print(obj.n)
    print(obj.a)
    print(obj.__dict__)
    #zbb
    #{'n': 'zbb'}
    

    2.对象操作对象空间属性

    1.对象查看对象的空间的所有属性

    obj = Human('zbb',18)
    print(obj.__dict__)
    

    2. 对象操作对象空间的属性

    obj = Human('zbb',18)
    增:
    obj.sex = 'laddy_boy'
    删:
    del obj.a
    改:
    obj.a = 1000
    查:
    print(obj.n)
    print(obj.__dict__)
    

    3.对象查看类中的属性

    obj = Human('zbb',18)
    # print(obj.mind)
    obj.mind = '无脑的'
    print(obj.mind)
    print(Human.mind)
    

    4.对象调用类中的方法

    class Human:
    
        mind = '有思想'
        language = '实用语言'
        def __init__(self,name,sex,age,hobby):
            self.n = name
            self.s = sex
            self.a = age
            self.h = hobby
    
        def work(self):
            print(self)
            print('人类会工作')
    
        def tools(self):
            print('人类会使用工具')
    
    obj = Human('barry','男',18,'运动')
    obj.work()
    obj.tools()
    

    5.self 是什么?

    self其实就是类中方法(函数)的第一个位置参数,只不过解释器会自动将调用这个函数的对象传给self。所以咱们把类中的方法的第一个参数约定俗成设置成self, 代表这个就是对象。
    

    一个类可以实例化多个对象

    obj1= Human('小胖','男',20,'美女')
    obj2= Human('相爷','男',18,'肥女')
    print(obj1,obj2)
    print(obj1.__dict__)
    print(obj2.__dict__)
    

    第二章 类空间问题以及类之间的关系

    1.何处可以添加对象属性

    class A:
        def __init__(self,name):
            self.name = name
    
        def func(self,sex):
            self.sex = sex
    
    # 类外面可以:
    obj = A('barry')
    obj.age = 18
    print(obj.__dict__)  # {'name': 'barry', 'age': 18}
    
    # 类内部也可以:
    obj = A('barry') # __init__方法可以。
    obj.func('男')  # func 方法也可以。
    
    

    2.何处可以添加类的静态属性

    class A:
        def __init__(self, name):
            self.name = name
    
        def func(self, sex):
            self.sex = sex
    
        def func1(self):
            A.bbb = 'ccc'
    
    
    # 类的外部可以添加
    
    A.aaa = 'djb'
    print(A.__dict__)
    
    # 类的内部也可以添加。
    
    A.func1(111)
    print(A.__dict__)
    
    

    3. 对象如何找到类的属性

    对象查找属性的顺序:先从对象空间找 ------> 类空间找 ------> 父类空间找 ------->.....

    类名查找属性的顺序:先从本类空间找 -------> 父类空间找--------> ........

    上面的顺序都是单向不可逆,类名不可能找到对象的属性。

    4.类与类之间的关系

    1. 依赖关系
    2. 关联关系
    3. 组合关系
    4. 聚合关系
    5. 实现关系
    6. 继承关系(类的三大特性之一:继承。)

    1.依赖关系

    主从之分

    依赖关系:将一个类的对象或者类名传到另一个类的方法使用。

    2.关联,组合,聚合关系

    1. 关联关系. 两种事物必须是互相关联的. 但是在某些特殊情况下是可以更改和更换的.
    2. 聚合关系. 属于关联关系中的⼀种特例. 侧重点是xxx和xxx聚合成xxx. 各⾃有各⾃的声明周期. 比如电脑. 电脑⾥有CPU, 硬盘, 内存等等. 电脑挂了. CPU还是好的. 还是完整的个体
    3. 组合关系. 给对象封装一个属性,属性值是另一个类的对象
    class  Boy:
    
        def __init__(self,name,girl=None):
            self.name = name
            self.girl=girl
    
        def hava_diner(self):
            if self.girl:
                print(f"{self.name}请{self.girl}吃饭")
            else:
                print("单身狗")
    
    
    live=Boy("qw")
    # live.hava_diner()
    live.girl="zxy"
    live.hava_diner()
    
    
    class  Boy:
    
        def __init__(self,name,girl=None):
            self.name = name
            self.girl=girl
    
        def hava_diner(self):
            if self.girl:
                print(f"{self.name}请{self.girl}吃饭")
            else:
                print("单身狗")
    
        def girl_skill(self):
            self.girl.skill()
    
    class Girl:
        def __init__(self,name):
            self.name=name
    
        def  skill(self):
            print(f"{self.name}能吃")
    zbb=Boy("zbb")
    # live.hava_diner()
    zxy =Girl("zxy")
    zbb.girl=zxy
    zbb.girl_skill()
    
    
    class  Game_role:
    
        def __init__(self,name,ad,hp):
            self.name=name
            self.ad=ad
            self.hp=hp
    
        def equipment(self,wea):
            self.weapon =wea   #组合关系
    
    
    class Weapon:
        def  __init__(self,name,ad):
            self.name = name
            self.ad  = ad
    
        def weapon_attack(self,p1,p2): #依赖关系
            p2.hp-=self.ad
            print(f"{p1.name}利用{self.name}给了{p2.name}一枪,{p2.name}掉了{self.ad}血,还剩{p2.hp}")
    
    gailun =Game_role("盖伦",10,100)
    yasuo =Game_role("剑豪",20,80)
    Sword = Weapon("大保健",16)
    Musket = Weapon('菊花枪',20)
    # 给游戏人物封装武器属性
    gailun.equipment(Sword)
    
    gailun.weapon.weapon_attack(gailun,yasuo)
    
    

    第三章 继承

    1.什么是面向对象的继承

    比较官方的说法就是:

    继承(英语:inheritance)是面向对象软件技术当中的一个概念。如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。 一般静态的面向对象编程语言,继承属于静态的,意即在子类别的行为在编译期就已经决定,无法在执行期扩充

    专业说法: 如果B类继承A类

    B类就称为子类,派生类

    A类称为父类,基类,超类

    通俗一点就是 子承父业

    # 继承的用法:
    class Aniaml:
        live = "123"
        def __init__(self,name,sex,age):
                self.name = name
                self.age = age
                self.sex = sex
    
    class Cat(Aniaml):
        pass
    
    class Dog(Aniaml):
        pass
    
    

    优点: 减少重复代码 .

    增加类之间的耦合度(耦合性不宜多,宜精)

    2.继承的分类

    在python2x版本中存在两种类.:
      ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
      ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
    python3x版本中只有一种类:
    python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object

    3.单继承

    1.类名,对象执行父类的方法

    class Animal:
    
        live = "有生命"
        def  __init__(self,name,sex,age):
            self.name =name
            self.sex =sex
            self.age =age
    
        def eat(self):
            print("chi")
    
    class Human(Animal):
        body = "有思想"
    #类名执行父类属性的方法(不常用)
    print(Human.live)
    Human.eat(1213)
    #子类执行父类的方法
    obj = Human("zbb","男","23") #相当于实例化
    print(obj.live)
    
    

    2.执行顺序

    p1 = Person('barry','男',18)
    # 实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。
    p1.eat()
    # 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法。
    
    

    3.同时执行子类以及父类方法

    第一种方法(不常用)

    class Animal:
    
    
        def eat(self):
            print("chi")
    
    class Human:
    
        def  __init__(self,name):
            self.name =name
        def eat(self):
            print(f"{self.name}需要吃饭")
            Animal.eat(self.name)
    
    obj = Human("zbb")
    obj.eat()
    
    

    第二种方法

    class Animal:
    
        def eat(self):
            print("chi")
    
    class Human(Animal):
        def  __init__(self,name):
            self.name =name
    
        def eat(self):
            print(f"{self.name}需要吃饭")
            super().eat()
    
    obj = Human("zbb")
    obj.eat()
    

    super() 重构父类的方法

    解决多重继承问题

    不需要明确给出任何基类的名字,它会自动找到所有直接基类,及其对应的方法.用于继承.

    super()的好处就是可以避免直接使用父类的名字.主要用于多重继承

    4.多继承

    在python2x版本中存在两种类.:
      ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
      ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
    python3x版本中只有一种类:
    python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object
    

    1.经典类的多继承

    经典类: 深度优先.从左至右,深度优先.

    不继承object类

    2.新式类的多继承

    继承object类

    class O:
        name = '1'
    
    class D(O):
        pass
    
    class E(O):
        name = '2'
        # pass
    class F(O):
        name = '3'
    
    class B(D,E):
        pass
    
    class C(E,F):
        pass
    
    class A(B,C):
        pass
    
    obj = A()
    print(obj.name)
    
    # mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
    # mro(A(B,C)) = [A] + merge(mro(B),mro(C),[B,C])
    
    
    总结:直接print 不需要什么算法
    print(A.mro())
    mro是继承付父类方法时的顺序表
    
    

    第四章 封装

    封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。

    所以,在使用面向对象的封装特性时,需要:

    • 将内容封装到某处
    • 从某处调用被封装的内容

    第一步:将内容封装到某处

    self 是一个形式参数,当执行 obj1 = Foo( ) 时,self 等于 obj1

    第二步:从某处调用被封装的内容

    调用被封装的内容时,有两种情况:

    • 通过对象直接调用
    • 通过self间接调用

    1、通过对象直接调用被封装的内容

    上图展示了对象 ojb1在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名

    class Foo:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
    
    obj1 = Foo("zbb",18)
    print(obj1.name) # 直接调用obj1对象的name属性
    print(obj1.age) # 直接调用obj1对象的age属性
    
    

    2、通过self间接调用被封装的内容

    执行类中的方法时,需要通过self间接调用被封装的内容

    class Foo:
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def func(self):
            print(self.name)
            print(self.age)
    
    
    obj1 = Foo("zbb",18)
    obj1.func() ## Python默认会将obj1传给self参数
    
    

    综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。

    第五章 多态

    多态,同一个对象,多种形态。python默认支持多态。

    鸭子类型

    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  Payment:
    
        def pay(self,money):
            raise  Exception("你的子类需要定义pay方法")
    		#pass
    
    class QQpay(Payment):
    
        def pay(self,money):
            print(f"使用qq支付了{money}")
    
    
    class Alipay(Payment):
        def  pay(self,money):
            print(f"使用阿里支付了{money}")
    
    
    class Wechat(Payment):
        def fuqian(self,money):
            print(f"使用微信支付了{money}")
    
    
    def pay(obj,money):  #统一接口
        obj.pay(money) # 这个函数就是统一支付规则,这个叫做: 归一化设计。
    
    obj1 = QQpay()
    obj2 = Alipay()
    obj3 = Wechat()
    pay(obj1,100)
    pay(obj2,200)
    
    # pay(obj3,200)  # 会直接找到父类 并发出错误
    
    
    from  abc import   ABCMeta,abstractmethod
    
    class  Payment(metaclass=ABCMeta):
        #抽象类 接口类  规范和约束  metaclass指定的是一个元类
        @abstractmethod
        def pay(self,money):
            pass #抽象方法
    
    
    class QQpay(Payment):
    
        def pay(self,money):
            print(f"使用qq支付了{money}")
    
    
    class Alipay(Payment):
        def  pay(self,money):
            print(f"使用阿里支付了{money}")
    
    
    class Wechat(Payment):
        def fuqian(self,money):
            print(f"使用微信支付了{money}")
        # def pay(self,money):#强制定义  不定义会报错
        #     pass
    
    def pay(obj,money): #统一接口
        obj.pay(money)
    
    obj3 = Wechat()   #实例化过程 就报错了
    
    

    总结: 约束. 其实就是⽗类对⼦类进⾏约束. ⼦类必须要写xxx⽅法. 在python中约束的⽅式和⽅法有两种:

    1. 使⽤抽象类和抽象⽅法, 由于该⽅案来源是java和c#. 所以使⽤频率还是很少的

    2.使⽤⼈为抛出异常的⽅案. 并且尽量抛出的是NotImplementError. 这样比较专业, ⽽且错误比较明确.(推荐)

    第七章 super()深入了解

    super是严格按照类的继承顺序执行!!!

    # super可以下一个类的其他方法
    # 严格按照类的mro顺序执行
    
    
    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(Foo,self).f1()
            #super(Info,self).f1() #()默认是
            print('in Info f1')
    
    obj = Info()
    obj.f1()
    
    
    
    

    第八章 带颜色的print

    书写格式: 开头部分:33[显示方式;前景色;背景色m + 结尾部分:33[0m

    ​ 注意:开头部分的三个参数:显示方式,前景色,背景色是可选参数,可以只写其中的某一个;另外由于表示三个参数不同含义的数值都是唯一的没有重复的,所以三个参数的书写先后顺序没有固定要求,系统都能识别;但是,建议按照默认的格式规范书写。

    ​ 对于结尾部分,其实也可以省略,但是为了书写规范,建议33[***开头,33[0m结尾。

    -------------------------------------------
    -------------------------------------------
    字体色     |       背景色     |      颜色描述
    -------------------------------------------
    30        |        40       |       黑色
    31        |        41       |       红色
    32        |        42       |       绿色
    33        |        43       |       黃色
    34        |        44       |       蓝色
    35        |        45       |       紫红色
    36        |        46       |       青蓝色
    37        |        47       |       白色
    -------------------------------------------
    -------------------------------
    显示方式     |      效果
    -------------------------------
    0           |     终端默认设置
    1           |     高亮显示
    4           |     使用下划线
    5           |     闪烁
    7           |     反白显示
    8           |     不可见
    -------------------------------
    
    

    数值表示的参数含义:

    显示方式: 0(默认值)、1(高亮)、22(非粗体)、4(下划线)、24(非下划线)、 5(闪烁)、25(非闪烁)、7(反显)、27(非反显)

    前景色: 30(黑色)、31(红色)、32(绿色)、 33(黄色)、34(蓝色)、35(洋 红)、36(青色)、37(白色)

    背景色: 40(黑色)、41(红色)、42(绿色)、 43(黄色)、44(蓝色)、45(洋 红)、46(青色)、47(白色)

    常见开头格式
    33[0m 默认字体正常显示,不高亮
    33[32;0m 红色字体正常显示
    33[1;32;40m 显示方式: 高亮 字体前景色:绿色 背景色:黑色
    33[0;31;46m 显示方式: 正常 字体前景色:红色 背景色:青色

    举例说明:

    1,

    print('33[1;35;0m字体变色,但无背景色 33[0m')  # 有高亮 或者 print('33[1;35m字体有色,但无背景色 33[0m')
    print('33[1;45m 字体不变色,有背景色 33[0m')  # 有高亮
    print('33[1;35;46m 字体有色,且有背景色 33[0m')  # 有高亮
    print('33[0;35;46m 字体有色,且有背景色 33[0m')  # 无高亮
    
    

    第九章 类的成员

    1.细分类的组成成员

    class A:
    
        company_name = 'zbb'  # 静态变量(静态字段)
        __iphone = '1353333xxxx'  # 私有静态变量(私有静态字段)
    
    
        def __init__(self,name,age): #特殊方法
    
            self.name = name  #对象属性(普通字段)
            self.__age = age  # 私有对象属性(私有普通字段)
    
        def func1(self):  # 普通方法
            pass
    
        def __func(self): #私有方法
            print(666)
    
    
        @classmethod  # 类方法
        def class_func(cls):
            """ 定义类方法,至少有一个cls参数 """
            print('类方法')
    
        @staticmethod  #静态方法
        def static_func():
            """ 定义静态方法 ,无默认参数"""
            print('静态方法')
    
        @property  # 属性
        def prop(self):
            pass
    
    

    2.类的私有成员

    对于每一个类的成员而言都有两种形式:

    • 公有成员,在任何地方都能访问
    • 私有成员,只有在类的内部才能方法

    私有成员和公有成员的访问限制不同

    1.静态字段(静态属性)

    ​ 公有静态字段:类可以访问;类内部可以访问;派生类中可以访问

    ​ 私有静态字段:仅类内部可以访问;

    class A:
        name = 'zbb'
        __name = "zmn"
        def func(self):
            print(self.name)
            print(self.__name)
    
    obj = A()
    
    obj.func()  #内部可以访问
    
    

    外部不能访问

    class A:
        name = 'zbb'
        __name = "zmn"
        def func(self):
            pass
    
    obj = A()
    
    print(obj.name)
    print(obj.__name) #报错
    print(A.__name) #报错
    
    

    2.对象属性

    公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问

    私有普通字段:仅类内部可以访问;

    class A:
    
        def __init__(self,name,pwd):
    
            self.name = name
            self.__pwd = pwd
    
        def md5(self):
            self.__pwd = self.__pwd + "123"
    obj = A('zbb',"123")
    print(obj.__pwd)  ###报错 不能在类外部以及派生类使用
    
    

    3.方法:

    公有方法:对象可以访问;类内部可以访问;派生类中可以访问

    私有方法:仅类内部可以访问;

    class  A:
        def func(self):
            self.__func()
            print("1")
        def __func(self):
            print("2")
    
    obj = A()
    obj.func()   #内部可以调用
    # obj.__func()  报错
    #####print(A._A__func)  #(不允许!!!)
    
    

    总结:

    私有成员来说: 当你遇到重要的数据,功能,(只允许本类使用的一些方法,数据)设置成私有成员.

    ps:非要访问私有成员的话,可以通过 对象._类__属性名,但是绝对不允许!!!*

    为什么可以通过._类__私有成员名访问呢?因为类在创建时,如果遇到了私有成员(包括私有静态字段,私有普通字段,私有方法)它会将其保存在内存时自动在前面加上_类名.

    3.类的其他方法

    实例方法

    定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法);

    调用:只能由实例对象调用。

    1.类方法

    定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);

    调用:实例对象和类对象都可以调用。

    类方法有什么用???

    ​ 得到类名可以实例化对象.

    ​ 可以操作类的属性.

    class  A:
    
        def func(self):
            print("实例方法")
    
        @classmethod
        def cls_func(cls):
            print(f"cls{cls}") #cls类名
            obj = cls()
            print(obj)  #打印A的内存地址
            print("类方法")
    
    A.cls_func()
    #obj = A()
    #obj.cls_func()
    # 类方法: 一般就是通过类名去调用的方法,并且自动将类名地址传给cls,
    # 但是如果通过对象调用也可以,但是传的地址还是类名地址.
    
    

    例题

    创建学生类,只要实例化一个对象,写一个类方法,统计一下具体实例化多少个学生?

    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('zbb', 12343243243) #
    obj1 = Student('zbb', 12343243243) #
    print(Student.getnum())
    
    

    2.静态方法

    使用装饰器@staticmethod。

    ​ 调用:实例对象和类对象都可以调用。

    # # 静态方法是不依赖于对象与类的,其实静态方法就是函数.
    # 保证代码的规范性,合理的划分.后续维护性高.
    #和在外面没有区别
    
    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())
    
    

    3.属性

    property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

    将动态方法 伪装 成了一个属性,虽然在代码级别上没有什么提升,但是让你看起来更合理

    例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
    
    成人的BMI数值:
    过轻:低于18.5
    正常:18.5-23.9
    过重:24-27
    肥胖:28-32
    非常肥胖, 高于32
      体质指数(BMI)=体重(kg)÷身高^2(m)
      EX:70kg÷(1.75×1.75)=22.86
    
    
    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 将执行一个函数需要函数名()变换成直接函数名.
    # 将动态方法 伪装 成了一个属性,虽然在代码级别上没有什么提升,但是让你看起来更合理.
    
    
    

    由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除

    class Foo:
        @property
        def AAA(self):
            print('get的时候运行我啊')
    
        @AAA.setter
        def AAA(self,value):
            print('set的时候运行我啊')
    
        @AAA.deleter
        def AAA(self):
            print('delete的时候运行我啊')
    
    #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
    f1=Foo()
    f1.AAA
    f1.AAA='aaa'
    del f1.AAA
    # get的时候运行我啊
    # set的时候运行我啊
    # delete的时候运行我啊
    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_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应
    
    f1=Foo()
    f1.AAA
    f1.AAA='aaa'
    del f1.AAA
    
    

    使用场景

    class Goods(object):
    
        def __init__(self):
            # 原价
            self.original_price = 100
            # 折扣
            self.discount = 0.8
    
        @property
        def price(self):
            # 实际价格 = 原价 * 折扣
            new_price = self.original_price * self.discount
            return new_price
    
        @price.setter
        def price(self, value):
            self.original_price = value
    
        @price.deltter
        def price(self, value):
            del self.original_price
    
    obj = Goods()
    obj.price         # 获取商品价格
    obj.price = 200   # 修改商品原价
    del obj.price     # 删除商品原价
    
    商品实例
    
    商品示例
    
    

    第十章 isinstace 与 issubclass

    isinstance(a,b):判断a是否是b类(或者b类的派生类)实例化的对象

    class A:
        pass
    
    class B(A):
        pass
    
    obj = B()
    
     
    print(isinstance(obj,B))
    print(isinstance(obj,A))
    
    isinstance
    
    

    isinstace(a,b) 判断的是 a类是否是b类 子孙类.**

    issubclass(a,b): 判断a类是否是b类(或者b的派生类)的派生类

    class A:
        pass
    
    class B(A):
        pass
    
    class C(B):
        pass
    
    print(issubclass(B,A))
    print(issubclass(C,A))
    
    issubclass
    
    

    思考:那么 list str tuple dict等这些类与 Iterble类 的关系是什么?

    from collections import Iterable
    
    print(isinstance([1,2,3], list))  # True
    print(isinstance([1,2,3], Iterable))  # True
    print(issubclass(list,Iterable))  # True
    
    # 由上面的例子可得,这些可迭代的数据类型,list str tuple dict等 都是 Iterable的子类。
    
    

    第十章 type与object联系

    type元类是获取该对象从属于的类,而type类比较特殊,Python原则是:一切皆对象,其实类也可以理解为'对象',而type元类又称作构建类,

    python中大多数内置的类(包括object)以及自己定义的类,都是由type元类创造的。

    print(type('abc'))
    print(type(True))
    print(type(100))
    print(type([1, 2, 3]))
    print(type({'name': 'zbb'}))
    print(type((1,2,3)))
    print(type(object))
    
    class A:
        pass
    
    print(isinstance(object,type))
    print(isinstance(A, type))
    
    
    type 与 object 的关系.
    print(type(object)) object类是type类的一个实例.
    object类是type类的父类.
    print(issubclass(type,object))
    
    

    第十一章 反射

    程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。

    python面向对象中的反射:

    通过字符串的形式操作对象相关的属性。

    python中的一切事物都是对象(都可以使用反射)

    四个可以实现自省的函数

    下列方法适用于类和对象(一切皆对象,类本身也是一个对象)

    对对象的反射

    class Foo:
        f="类的静态变量"
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def  say_hi(self):
            print(f"hello {self.name}")
    #实例化对象
    obj = Foo("zbb",23)
    
    #检测是否含有某属性
    print(hasattr(obj,"name"))
    print(hasattr(obj,"say_hi"))
    # 获得属性(可以获得是字符串)
    n = getattr(obj,"name")
    # print(obj.name)
    print(n)
    func=getattr(obj,'say_hi')
    # obj.say_hi()
    func()
    
    # print(getattr(obj,'aaaaaaaa')) #报错
    print(getattr(obj,'aaaaaaaa','不存在啊')) #报错内容自己定义
    # 设置属性
    setattr(obj,'sb',True)
    setattr(obj,'show_name',lambda self:self.name+'nb')
    print(obj.__dict__)
    print(obj.show_name(obj))
    #删除属性
    delattr(obj,'age')
    delattr(obj,'show_name')
    # delattr(obj,'show_name111')#不存在,则报错
    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")
    
    if  hasattr(A,"country"):
        print(getattr(A,"country"))
    
    if  hasattr(A,"func"):
        obj = A("zbb","18")
        getattr(obj,"func")()
    
    
    

    当前模块的反射

    import sys
    
    def s1():
        print('s1')
    
    def s2():
        print('s2')
    
    this_module = sys.modules[__name__] #本模块这个对象
    
    hasattr(this_module, 's1')
    getattr(this_module, 's2')
    
    

    在当前模块中一次性执行4个函数

    def func1():
        print('in func1')
    
    def func2():
        print('in func2')
    
    def func3():
        print('in func3')
    
    def func4():
        print('in func4')
    
    import sys
    
    func_lst = [f'func{i}' for i in range(1,5)]
        # print(func_lst)
    for func in func_lst:
        getattr(sys.modules[__name__],func)()
    
    

    对其他模块的反射

    #一个模块中的代码
    def test():
        print('from the test')
    
    # 另一个模块中的代码
    import module_test as obj
    
    #obj.test()
    
    print(hasattr(obj,'test'))
    
    getattr(obj,'test')()
    
    

    反射的应用:

    了解了反射的四个函数。那么反射到底有什么用呢?它的应用场景是什么呢?

    现在让我们打开浏览器,访问一个网站,你单击登录就跳转到登录界面,你单击注册就跳转到注册界面,等等,其实你单击的其实是一个个的链接,每一个链接都会有一个函数或者方法来处理

    class User:
    
        user_list = [('login','登录'),('register','注册'),('save', '存储')]
    
        def login(self):
            print('欢迎来到登录页面')
    
        def register(self):
            print('欢迎来到注册页面')
    
        def save(self):
            print('欢迎来到存储页面')
    
    
    while 1:
        choose = input('请输入序号: 
    1: 登录
    2: 注册
    3: 存储
    ').strip()  # 1
        obj = User()
        getattr(obj, obj.user_list[int(choose)-1][0])()  # getattr(obj,'login')
    
    

    第十二章 函数 vs 方法

    1.通过打印函数(方法)名确定(了解)

    def func():
        pass
    
    class A:
        def func(selfs):
            pass
    
    
    print(func)
    print(A.func)#通过类名调用的类中的实例方法叫函数
    <function func at 0x00000252B19DC2F0>
    <function A.func at 0x00000252B1B997B8>
    obj= A()
    print(obj.func)#通过对象调用的类中的实例方法叫方法.
    
    

    2 通过types模块验证

    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这个类实例化出来的.
    
    

    3 静态方法是函数

    4 函数与方法的区别

    那么,函数和方法除了上述的不同之处,我们还总结了一下几点区别。

    (1)函数的是显式传参的。

    (2)函数则跟对象无关。

    (3)方法中的数据则是隐形传参.

    (4)方法可以操作类内部的数据。

    (5)方法跟对象是关联的。如我们在用strip()方法是,是不是都是要通过str对象调用,比如我们有字符串s,然后s.strip()这样调用。是的,strip()方法属于str对象。

    我们或许在日常中会口语化称呼函数和方法时不严谨,但是我们心中要知道二者之间的区别。

    在其他语言中,如Java中只有方法,C中只有函数,C++么,则取决于是否在类中。

    第十三章 双下方法

    定义:双下方法是特殊方法

    双下方法主要是python源码程序员使用的,

    我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码。

    调用:不同的双下方法有不同的触发方式,就好比盗墓时触发的机关一样,不知不觉就触发了双下方法,例如:_init

    1. len

    class  B:
        def __init__(self,name,age):
            self.name = name
    
        def __len__(self):
            print(self.__dict__)
            return  len(self.__dict__) #必须要加
    
    b = B("zbb",28)
    
    print(len(b)) #len()触发调用
    
    

    2.hash

    class A:
    
        pass
    
    obj = A()
    
    print(hash(obj))
    print(hash('fdsaf')) # hash()触发调用
    
    

    3.str重点

    如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

    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("zbb",18)
    print(f'{a.name},{a.age}') #打印对象名触发__str__方法
    print(str(a)) #直接str转化也可以触发.
    
    

    4.repr

    如果一个类中定义了__repr__方法,那么在repr(对象) 时,默认输出该方法的返回值。

    print('我叫%s' % ('zbb'))
    print('我叫%r' % ('zbb')) #保留括号里的原来的样子
    print(repr('fdsaf'))
    # 我叫zbb
    # 我叫'zbb'
    # '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('zbb',18)
    
    # print(a)
    print(repr(a)) #print(repr(对象名))  触发   
    
    

    5.call重点

    class Foo:
    
        def __init__(self):
            pass
    
        def __call__(self, *args, **kwargs):
            print('__call__')
    
    obj = Foo()
    obj() # 对象名()   或者 类名()()  触发
    # Foo()()
    
    

    6.eq

    class A:
        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) # 对象名 == 对象名    会触发
    节省内存
    
    

    7.del

    class A:
    
        def __del__(self):
            print(666)
    
    obj = A()
    del obj
    # del 变量名 或者 类 或者 方法名时会执行     
    #不需要去程序员去关心,垃圾处理机制帮助处理
    
    

    8.new 重点

    class A:
    
        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
    
    a = A()
    # 1. 先触发 object的__new__方法,此方法在内存中开辟一个对象空间.
    # 2. 执行__init__方法,给对象封装属性.
    
    
    # python中的设计模式: 单例模式
    
    # 一个类只允许实例化一个对象.
    class A:
    
        pass
    obj = A()
    print(obj)
    obj1 = A()
    print(obj1)
    obj2 = A()
    print(obj2)  #地址都不同
    
    

    手写单例模式

    方便对实例个数的控制并节约系统资源
    
    
    class A:
        __msg = None  # 用来记录对象信息
    
        def __init__(self,name):
            self.name = name
    
        def __new__(cls, *args, **kwargs):
            if not cls.__msg:  # 当 __msg 为 None 时,证明是第一次创建对象空间
                # cls.__msg = super().__new__(cls)  # 调用父类的__new__方法。 记得参数为 cls(类本身)
                cls.__msg = object.__new__(cls)
            return cls.__msg  # 将对象空间返回
    
    
    
    
    a = A("zbb")
    a1 = A("zxy")
    print(a.name)
    print(a1.name)  # 两个地址相同
    
    
    
    

    9.item

    # __item__系列
    # __getitem__  __setitem__  __delitem__  对对象做类似于字典的(增删改查)触发__item__系列
    # __delattr__ del obj.属性  就会触发此方法
    class Foo:
        def __init__(self,name):
            self.name=name
    
        def __getitem__(self, item):
            print(self.__dict__[item])
    
        def __setitem__(self, key, value):
            self.__dict__[key]=value
        def __delitem__(self, key):
            print('del obj[key]时,我执行')
            self.__dict__.pop(key)
        def __delattr__(self, item):
            print('del obj.key时,我执行')
            self.__dict__.pop(item)
    
    f1=Foo('sb')
    f1['age']=18
    f1['age1']=19
    del f1.age1
    del f1['age']
    f1['name']='alex'
    print(f1.__dict__)
    
    

    10.enter exit

    上下文管理

    # 实例化对象的第二种方式: 必须基于 __enter__ 以及 __exit__这个两个方法.
    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)  # 第四步
    
    

    11.iter

    class A:
    
        def __init__(self,name):
            self.name = name
    
        def __iter__(self):
            for i in range(10):
                yield i
    
    
    obj = A('zbb')  # obj 一个可迭代对象
    # print('__iter__' in dir(obj))
    for i in obj:
        print(i)
    
    
    class A:
    
        def __init__(self,name):
            self.name = name
    
        def __iter__(self):
            for i in range(10):
                yield i
    
    obj = A('zbb')  # obj 一个可迭代对象
    
    o = iter(obj)
    print(next(o))
    print(next(o))
    print(next(o))
    
    
  • 相关阅读:
    linux grep命令
    PHP 利用simplexml_load_file 读取XML对应的字段 然后存入mysql数据库
    php 设计模式之单类模式
    Mac C#开发工具Rider安利与环境配置教程
    模拟,贪心,枚举(二)
    模拟,贪心,枚举
    10.10 review
    review 10.9
    10.6 review
    9.28 review
  • 原文地址:https://www.cnblogs.com/zdqc/p/11278575.html
Copyright © 2020-2023  润新知