• 面向对象编程


    面向对象基础

    面向对象编程介绍

    '''
    面向过程的编程思想
        核心过程二字,过程指的是解决问题的步骤,即先干什么再干什么后干什么
        基于该思想编写程序就好比在设计一条流水线,是一种机械式的思维方式
    
        优点:复杂的问题流程化进而简单化
        缺点:可扩展性差
    
    面向对象的编程思想
        核心是对象二字,对象是特征与技能的结合体
        基于该思想编写程序(脑子始终想的是对象二字)就好比在创造一个世界,世界是由一个个对象组成,在上帝眼里任何存在的事物都是对象,任何不存在的事物也都可以造出来,是一种上帝式的思维方式
    
        优点: 可扩展性强
        缺点: 编程的复杂度要高与面向过程
    
    
    类:
        对象是特征与技能的结合体,而类则是一系列对象相同的特征与技能的结合体
        强调:
            1.对象是具体存在的事物,而类则一个抽象的概念
            2.站在不同的角度总结出的类与对象是不同的
    
    在现实世界中:先有一个个具体存在的对象,然后随着人类文明的发展才总结出类的概念
    在程序中: 先定义类,后调用类来产生对象
    
    站在老男孩选课系统的角度
    总结出现实世界中的老男孩学生对象:
        学生对象1
            特征
                school='oldboy'
                name='李铁蛋'
                age=18
                sex='male'
            技能
                选课
    
        学生对象2
            特征
                school='oldboy'
                name='赵钢弹'
                age=38
                sex='female'
            技能
                选课
    
        学生对象3
            特征
                school='oldboy'
                name='刘银弹'
                age=28
                sex='male'
            技能
                选课
    
        老师对象1
            特征
                school='oldboy'
                name='Egon'
                age=18
                sex='male'
                level=10
            技能
                打分
    
    总结现实世界中的老男孩学生类
        相同的特征
            school='oldboy'
        相同的技能
            选课
    
    在程序中....
    '''
    

    类的使用

    '''
    站在老男孩选课系统的角度
    总结出现实世界中的老男孩学生对象:
        学生对象1
            特征
                school='oldboy'
                name='李铁蛋'
                age=18
                sex='male'
            技能
                选课
    
        学生对象2
            特征
                school='oldboy'
                name='赵钢弹'
                age=38
                sex='female'
            技能
                选课
    
        学生对象3
            特征
                school='oldboy'
                name='刘银弹'
                age=28
                sex='male'
            技能
                选课
    
    总结现实世界中的老男孩学生类
        相同的特征
            school='oldboy'
        相同的技能
            选课
    '''
    # 在程序中
    # 1. 先定义类
    class OldboyStudent:
        #相同的特征
        school = 'oldboy'
        #相同的技能
        def choose_course(self):
            print('choosing course')
        # print('===>>>')
        
    # 类是一系列对象相同的特征(变量)与技能(函数)的结合体,即类体中最常见的就是变量与函数的定义
    # 但其实类体中是可以存在任意python代码的
    # 类体代码会在类定义阶段立即执行,会产生一个类名称空间,用来将类体代码执行过程中产生的名字都丢进去,查看方式如下
    print(OldboyStudent.__dict__) # 查看类的名称空间
    print(OldboyStudent.school) # print(OldboyStudent.__dict__['school'])
    print(OldboyStudent.choose_course)
    OldboyStudent.school='OLDBOY' # OldboyStudent.__dict__['school']='OLDBOY'
    OldboyStudent.country='China' # OldboyStudent.__dict__['country']='China'
    del OldboyStudent.country # del OldboyStudent.__dict__['country']
    print(OldboyStudent.__dict__)
    
    OldboyStudent.choose_course(123123)
    # 总结:
    # 1. 类本质就是一个名称空间,或者说是一个用来存放变量与函数的容器
    # 2. 类的用途之一就是当做名称空间从其内部取出名字来使用
    # 3. 类的用途之二是调用类来产生对象
    
    
    #2. 后调用类来产生对象
    

    对象的使用

    '''
    学生对象1
            特征
                school='oldboy'
                name='李铁蛋'
                age=18
                sex='male'
            技能
                选课
    
        学生对象2
            特征
                school='oldboy'
                name='赵钢弹'
                age=38
                sex='female'
            技能
                选课
    
        学生对象3
            特征
                school='oldboy'
                name='刘银弹'
                age=28
                sex='male'
            技能
                选课
    '''
    
    class OldboyStudent:
        #相同的特征
        school = 'oldboy'
        #相同的技能
        def choose_course(self):
            print('choosing course')
    
    # 2. 后调用类来产生对象:
    # 调用类的过程称之为类的实例化,调用类的返回值称之为类的一个对象/实例
    
    # 调用类发生了?
    # 1. 会产生一个对象,然后返回
    stu1=OldboyStudent()
    stu2=OldboyStudent()
    stu3=OldboyStudent()
    # print(stu1.__dict__)
    # print(stu2.__dict__)
    # print(stu3.__dict__)
    
    # 为对象定制自己独有的特征
    '''
    # name='李铁蛋'
    # age=18
    # sex='male'
    stu1.name='李铁蛋'
    stu1.age=18
    stu1.sex='male'
    print(stu1.__dict__)
    
    # name='赵钢弹'
    # age=38
    # sex='female'
    stu2.name='赵钢弹'
    stu2.age=38
    stu2.sex='female'
    print(stu2.__dict__)
    
    # name='刘银弹'
    # age=28
    # sex='male'
    stu3.name='刘银弹'
    stu3.age=28
    stu3.sex='male'
    print(stu3.__dict__)
    '''
    
    # 为对象定制自己独有的特征,简化方案一:
    '''
    def init(obj,name,age,sex):
        obj.name = name
        obj.age = age
        obj.sex = sex
    
    # stu1.name='李铁蛋'
    # stu1.age=18
    # stu1.sex='male'
    init(stu1,'李铁蛋',18,'male')
    
    # stu2.name='赵钢弹'
    # stu2.age=38
    # stu2.sex='female'
    init(stu2,'赵钢弹',38,'female')
    
    # stu3.name='刘银弹'
    # stu3.age=28
    # stu3.sex='male'
    init(stu3,'刘银弹',28,'male')
    
    print(stu1.__dict__)
    print(stu2.__dict__)
    print(stu3.__dict__)
    '''
    
    # 为对象定制自己独有的特征,简化方案二:
    class OldboyStudent:
        #相同的特征
        school = 'oldboy'
        
        #           stu1,'李铁蛋',18,'male'
        def __init__(obj, name, age, sex):
            obj.name = name #stu1.name='李铁蛋'
            obj.age = age   #stu1.age=18
            obj.sex = sex   #stu1.sex='male'
    
        #相同的技能
        def choose_course(self):
            print('choosing course')
    
    # 调用类发生了
    # 1. 先产生一个空对象stu1,然后返回
    # 2. 触发类中函数__init__的执行,将对象连同调用类括号内指定的参数一同传入__init__(stu1,'李铁蛋',18,'male')
    
    stu1=OldboyStudent('李铁蛋',18,'male') #__init__(stu1,'李铁蛋',18,'male')
    stu2=OldboyStudent('赵钢弹',38,'female') #__init__(stu2,'赵钢弹',38,'female')
    stu3=OldboyStudent('刘银弹',28,'male') #__init__(stu3,'刘银弹',28,'male')
    
    # print(stu1.__dict__)
    # print(stu2.__dict__)
    # print(stu3.__dict__)
    # 总结__init__的功能: 是在实例化时就为对象初始自己独有的特征
    # 注意:不能有返回值
    
    # stu1.xxx=111
    # print(stu1.__dict__)
    
    

    属性查找

    xxx=33333
    class OldboyStudent:
        school = 'oldboy'
        # xxx=2222
        yyy=333
        count=0
    
        def __init__(obj, name, age, sex):
            # print(OldboyStudent.yyy)
            # print(obj.yyy)
    
            OldboyStudent.count+=1 #实现对对象的引用计数
            obj.name = name #stu1.name='李铁蛋'
            obj.age = age   #stu1.age=18
            obj.sex = sex   #stu1.sex='male'
    
        def choose_course(self):
            print('choosing course')
    
    # 1. 属性查找顺序
    stu1=OldboyStudent('李铁蛋',18,'male')
    print(stu1.__dict__)
    print(OldboyStudent.__dict__)
    stu1.xxx=111
    print(stu1.__dict__)
    # 先从对象自己的名称空间找,没有则去所属的类中找
    print(stu1.xxx)
    
    # 2.
    stu1=OldboyStudent('李铁蛋',18,'male')
    stu2=OldboyStudent('赵钢弹',38,'female')
    stu3=OldboyStudent('刘银弹',28,'male')
    # print(stu1.count)
    # print(stu2.count)
    # print(stu3.count)
    # print(OldboyStudent.count)
    
    # 类中定义的变量是所有对象共享的,对象可以来用,类也可以来使用,类一旦改变自己的数据属性的值,所有的对象都能感知到
    # print(id(stu1.school))
    # print(id(stu2.school))
    # print(id(stu3.school))
    # print(id(OldboyStudent.school))
    
    stu1.school=123  #只改变对象中的变量不会影响类中的变量值
    # OldboyStudent.school='OLDBOY' #改变类会影响到所有对象中的值
    # print(stu1.__dict__)
    # print(stu2.__dict__)
    # print(stu3.__dict__)
    # print(OldboyStudent.__dict__)
    #
    # print(OldboyStudent.school)
    # print(stu1.school)
    # print(stu2.school)
    # print(stu3.school)
    
    # print(id(stu1.choose_course))
    # print(id(stu2.choose_course))
    # print(id(stu3.choose_course))
    

    绑定方法

    # 类中定义的变量是类的数据属性,类可以用,对象也可以用,大家都指向同一个内存地址,类变量值一旦改变所有对象都跟着变
    
    # 类中定义的函数是类的函数属性,类可以用,类来调用就是一个普通的函数,但其实类中定义的函数是给对象用的,而且是绑定给对象用的
    # 绑定???
    class OldboyStudent:
        school = 'oldboy'
    
        def __init__(self, name, age, sex):
            self.name = name #stu1.name='李铁蛋'
            self.age = age   #stu1.age=18
            self.sex = sex   #stu1.sex='male'
    
        def choose_course(self,x): #self=stu1
            print('%s choosing course' %self.name)
    
    stu1=OldboyStudent('李铁蛋',18,'male')
    stu2=OldboyStudent('赵钢弹',38,'female')
    stu3=OldboyStudent('刘银弹',28,'male')
    
    # 1. 类的函数: 该传几个参数就传几个
    # print(OldboyStudent.__init__)
    # print(OldboyStudent.choose_course)
    # OldboyStudent.choose_course(stu1)
    
    # 2. 绑定方法,指向类的函数: 特殊之处是绑定给谁就应该由谁来调用,谁来调用就会将谁当做第一个参数自动传入
    # print(stu1.choose_course)
    # print(stu2.choose_course)
    # print(stu3.choose_course)
    
    # stu1.choose_course(123) # OldboyStudent.choose_course(stu1,123)
    # stu2.choose_course(123)
    # stu3.choose_course(123)
    # stu1.choose_course() #这样会报错,因为没有给x传参
    

    一切皆对象

    # 在python3中统一了类与类型的概念
    class Foo:
        pass
    # print(Foo)
    # obj=Foo()
    # print(type(obj))
    
    # print(int)
    # age=10 #age=int(10)
    # print(type(age))
    
    l1=[1,2,3] #l1=list([1,2,3])
    # print(type(l1))
    # l1.append(4)
    # print(l1)
    
    l1.append(4) # 相当于 list.append(l1,4)
    print(l1)
    
    l2=['a','b','c'] # l2=list(['a','b','c'])
    l2.append('d')
    

    三大特性之一:继承

    继承介绍

    '''
    1 什么是继承
        继承一种新建类的方式,新建的类称之为子类/派生类,被继承的类称之为父类基类超类
    
        python中继承的特点:
            1. 子类可以遗传/重用父类的属性
            2. python中一个子类可以同时继承多个父类
            3. 在继承背景下去说,python中的类分为两种:新式类,经典类
                新式类: 但凡继承了object的类Foo,以及该类的子类...都是新式类
                    在python3中一个类即便是没有显式地继承任何类,默认就会继承object
                    即python3中所有的类都是新式类
    
                经典类:没有继承object的类,以及该类的子类...都是经典类
                    在python2中才区分新式类与经典类,
                    在python2中一个类如果没有显式地继承任何类,也不会继承object
    
    2 为何要用继承
        减少类与类之间代码冗余
    
    3 如何用继承
    '''
    class Parent1(object): # 父类
        pass
    
    class Parent2(object): # 父类
        pass
    
    class Sub1(Parent1): # 子类,继承父类
        pass
    
    class Sub2(Parent1,Parent2): # 子类,多继承父类
        pass
    
    print(Parent1.__bases__) #(<class 'object'>,)
    print(Parent2.__bases__) #(<class 'object'>,)
    print(Sub1.__bases__) #(<class '__main__.Parent1'>,)
    print(Sub2.__bases__) #(<class '__main__.Parent1'>, <class '__main__.Parent2'>)
    
    
    class Parent1(object):
        xxx=333
    class Sub1(Parent1):
        # xxx=222  # 333
        pass
    obj=Sub1()
    # obj.xxx=111  # 222
    print(obj.xxx)  # 111
    
    # 问题:
    # 1 子类如何重用父类的属性
    # 2 在继承背景下,属性查找的优先级
    # 3 新式类与经典类在属性查找上的区别
    

    利用继承来解决类与类之间代码冗余问题

    class OldboyPeople:  # 父类(=子类1+子类2)
        school = 'Oldboy'
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    class OldboyStudent(OldboyPeople):  # 子类1
        # def __init__(self, name, age, sex, score=0):
        #     self.name = name
        #     self.age = age
        #     self.sex = sex
        #     self.score = score
        def choose_course(self):
            print('%s choosing course' % self.name)
    
    class OldboyTeacher(OldboyPeople):  # 子类2
        # def __init__(self,name,age,sex,level):
        #     self.name=name
        #     self.age=age
        #     self.sex=sex
        #     self.level=level
        def score(self,stu,num):
            stu.score=num
    
    stu1=OldboyStudent('刘二蛋',38,'male')
    print(stu1.__dict__)
    
    tea1=OldboyTeacher('egon',18,'male')
    print(tea1.__dict__)
    
    

    在子类派生的新方法中重用父类功能的方式一

    # 在子类派生出的新方法中重用父类功能的方式一:
    # 指名道姓地引用某一个类中的函数
    # 总结:
    # 1. 与继承无关
    # 2. 访问是类的函数,没有自动传值的效果
    class OldboyPeople:
        school = 'Oldboy'
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    class OldboyStudent(OldboyPeople):
        def __init__(self, name, age, sex, score=0):
            OldboyPeople.__init__(self,name,age,sex)
            self.score = score
        def choose_course(self):
            print('%s choosing course' % self.name)
    
    class OldboyTeacher(OldboyPeople):
        def __init__(self,name,age,sex,level):
            OldboyPeople.__init__(self,name,age,sex)
            self.level=level
        def score(self,stu,num):
            stu.score=num
    
    stu1=OldboyStudent('刘二蛋',38,'male')
    print(stu1.__dict__)
    
    tea1=OldboyTeacher('egon',18,'male',10)
    print(tea1.__dict__)
    

    在单继承背景下的属性查找

    
    # 在单继承背景下属性的查找优先级:对象->对象的类->父类->父类.....
    class Foo:
        # xxx=444
        pass
    class Bar1(Foo):
        # xxx=333
        pass
    class Bar2(Bar1):
        # xxx=222
        pass
    obj=Bar2()
    # obj.xxx=111
    print(obj.xxx)
    
    class Foo:
        def f1(self):
            print('Foo.f1')
        def f2(self):
            print('Foo.f2')
            self.f1() #obj.f1()
    
    class Bar(Foo):
        def f1(self):
            print('Bar.f1')
    
    obj=Bar()
    obj.f2()
    '''
    Foo.f2
    Bar.f1
    '''
    

    在多继承背景下的属性查找

    # 在多继承背景下属性的查找优先级:
    # 如果一个子类继承多个分支(多个分支没有共同继承一个非object的类)
    # 此时属性的查找优先级是:对象->对象的类->按照从左往右的顺序一个分支一个分支的找下去
    
    # 第四层:
    class G:
        # x = 'G'
        pass
    
    # 第三层
    class E(G):
        # x = 'E'
        pass
    class F:
        # x = 'F'
        pass
    
    # 第二层
    class B(E):
        # x = 'B'
        pass
    class C(F):
        # x = 'C'
        pass
    class D:
        # x = 'D'
        pass
    
    # 第一层
    class A(B, C, D):
        # x = 'A'
        pass
    
    obj = A()
    # obj.x = 111
    print(obj.x)
    
    # 菱形继承问题:
    # 新式类 : 广度优先查找,从左往右一个分支一个分支的查找,在最后一个分支才去查找顶级类
    # 经典类 : 深度优先查找,从左往右一个分支一个分支的查找,在第一个分支就查找顶级类
    # 第四层:
    class G(object):
        # x = 'G'
        pass
    
    # 第三层
    class E(G):
        # x = 'E'
        pass
    class F(G):
        # x = 'F'
        pass
    
    # 第二层
    class B(E):
        # x = 'B'
        pass
    class C(F):
        # x = 'C'
        pass
    class D(G):
        # x = 'D'
        pass
    
    # 第一层
    class A(B, C, D):
        # x = 'A'
        pass
    
    obj=A()
    # obj.x=111
    print(obj.x)
    #新式类(广度优先): obj->A->B->E->C-F->D->G->object
    #经典类(深度优先): obj->A->B->E->G->C-F->D
    
    # python专门为新式类内置了一个mro的方法,用来查看c3算法的计算结果,结果是??
    print(A.mro())
    

    在子类派生的新方法中重用父类功能的方式二

    # 在子类派生出的新方法中重用父类功能的方式二:super()必须在类中用
    # 在python2中:super(自己的类名,自己的对象)
    # 在python3中:super()
    # 调用该函数会得到一个特殊的对象,该对象专门用来访问父类中的属性,!!!完全参照mro列表!!!!
    # 总结:
    # 1. 严格依赖继承的mro列表
    # 2. 访问是绑定方法,有自动传值的效果
    
    class OldboyPeople:
        school = 'Oldboy'
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
    class OldboyStudent(OldboyPeople):
        def __init__(self, name, age, sex, score=0):
            super(OldboyStudent,self).__init__(name,age,sex)
            self.score = score
        def choose_course(self):
            print('%s choosing course' % self.name)
    class OldboyTeacher(OldboyPeople):
        def __init__(self,name,age,sex,level):
            super().__init__(name,age,sex)
            self.level=level
        def score(self,stu,num):
            stu.score=num
    stu1=OldboyStudent('刘二蛋',38,'male')
    print(stu1.__dict__)
    tea1=OldboyTeacher('egon',18,'male',10)
    print(tea1.__dict__)
    
    
    class A:
        def f1(self):
            print('A.f1')
            super().f2()
    class B:
        def f2(self):
            print('B.f2')
    class C(A,B):
        def f2(self):
            print('C.f2')
    obj=C()
    print(C.mro())
    obj.f1()  # 结果要根据mro中的值来判断
    '''
    [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
    A.f1
    B.f2
    '''
    

    继承总结

        1. 什么是继承
            继承是一种新建类的方式,新建的类称之为子类/派生类,被继承的类称之为父类/基类/超类
    
            继承有3个特点:
                1. 子类可以遗传/重用父类的属性(解决类与类之间代码冗余的问题)
                2. 在python中一个子类可以同时继承多个父类
                3. 在继承的背景下,类分为两种:新式类,经典类
                    新式类:但凡继承object类的子类,以及该子类的子子孙孙都是新式类
                        在python3中一个类即便是没有显式地继承任何类,默认就继承object类,
                        即在python3中所有类都是新式类
                    经典类:没有继承object类的子类,以及该子类的子子孙孙都是经典类
                        强调:只有在python2中才有经典类
                        在python2中如果一个类没有显式地继承任何类,并不会自动继承object类
    
        2. 为何要用继承:减少类与类之间的代码冗余
    
        3. 如何继承
            class Foo:
                pass
            class Bar(Foo):
                pass
    
            #obj=Bar()
            #obj.x
    
            Bar.x
    
        4. 属性查找
            在没有出现菱形继承的情况下,属性的查找是按照从左往右的顺序一个分支一个分支的找下去
            在出现菱形继承(一个子类继承的多个分支最终汇聚到一个非object类)的情况下,
                新式类:广度优先查找,按照从左往右的顺序一个分支一个分支的找下去,在最后一个分支才去查找顶级类
                经典类:深度优先查找,按照从左往右的顺序一个分支一个分支的找下去,在第一个分支就查找顶级类
    
    
        5. 派生
            在子类中定义自己的属性,如果与父类的属性重名,那以自己的为准.
    
            在子类派生的新方法中重用父类的功能:
                方式一:指名道姓地调用某一个类的函数
                    特点:
                        1. 与继承无关
                        2. 没有自动传值的效果
    
                方式二:super()得到一个特殊的对象,该对象专门用来引用父类的属性
                    特点:
                        1. 严格依赖继承,完全参照mro
                        2. 有自动传值的效果
    

    组合

    '''
    1. 什么是组合
        组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象
        class Foo:
            pass
    
        class Bar:
            pass
    
        obj=Foo()
        obj.attr=Bar()
    
        obj.xxx
        obj.attr.yyy
    
    2. 为何要用组合
        通过为某一个对象添加属性(属性的值是另外一个类的对象)的方式,可以间接地将两个类关联/整合/组合到一起
        从而减少类与类之间代码冗余
        class Foo1:
            pass
        class Foo2:
            pass
        class Foo3:
            pass
    
        class Bar:
            pass
    
        obj_from_bar=Bar()
    
        obj1=Foo1()
        obj2=Foo2()
        obj3=Foo3()
    
        obj1.attr1=obj_from_bar
        obj2.attr2=obj_from_bar
        obj3.attr3=obj_from_bar
    
    3. 如何用组合
    class OldboyPeople:
        school = 'Oldboy'
    
        def __init__(self,name,age,sex,):
            self.name = name
            self.age = age
            self.sex = sex
    
    class OldboyStudent(OldboyPeople):
        def __init__(self, name, age, sex,score=0):
            OldboyPeople.__init__(self,name,age,sex)
            self.score = score
    
        def choose_course(self):
            print('%s choosing course' % self.name)
    
    class OldboyTeacher(OldboyPeople):
        def __init__(self,name,age,sex,level):
            OldboyPeople.__init__(self,name,age,sex)
            self.level=level
    
        def score(self,stu,num):
            stu.score=num
    
    class Course:
        def __init__(self,c_name,c_price,c_period):
            self.c_name = c_name
            self.c_price = c_price
            self.c_period = c_period
    
        def tell_info(self):
            print('<课程名:%s 价钱:%s 周期:%s>' %(self.c_name,self.c_price,self.c_period))
    
    # 创建课程对象
    python=Course('python全栈开发',1900,'5mons')
    linux=Course('linux架构师',900,'3mons')
    
    stu1=OldboyStudent('刘二蛋',38,'male')
    stu1.course=python
    # print(stu1.__dict__)
    stu1.course.tell_info()
    
    tea1=OldboyTeacher('egon',18,'male',10)
    tea1.course=python
    # print(tea1.__dict__)
    tea1.course.tell_info()
    '''
    
    class OldboyPeople:
        school = 'Oldboy'
    
        def __init__(self,name,age,sex,):
            self.name = name
            self.age = age
            self.sex = sex
    
    class OldboyStudent(OldboyPeople):
        def __init__(self, name, age, sex,score=0):
            OldboyPeople.__init__(self,name,age,sex)
            self.score = score
            self.courses=[]
    
        def choose_course(self):
            print('%s choosing course' % self.name)
    
        def tell_all_course(self):
            print(('学生[%s]选修的课程如下' %self.name).center(50,'='))
            for obj in self.courses:
                obj.tell_info()
            print('='*60)
    
    class OldboyTeacher(OldboyPeople):
        def __init__(self,name,age,sex,level):
            OldboyPeople.__init__(self,name,age,sex)
            self.level=level
            self.courses=[]
    
        def score(self,stu,num):
            stu.score=num
    
        def tell_all_course(self):
            print(('老师[%s]教授的课程如下' %self.name).center(50,'*'))
            for obj in self.courses:
                obj.tell_info()
            print('*'*70)
    
    class Course:
        def __init__(self,c_name,c_price,c_period):
            self.c_name = c_name
            self.c_price = c_price
            self.c_period = c_period
    
        def tell_info(self):
            print('<课程名:%s 价钱:%s 周期:%s>' %(self.c_name,self.c_price,self.c_period))
    
    # 创建课程对象
    python=Course('python全栈开发',1900,'5mons')
    linux=Course('linux架构师',900,'3mons')
    
    stu1=OldboyStudent('刘二蛋',38,'male')
    stu1.courses.append(python)
    stu1.courses.append(linux)
    # print(stu1.courses)
    stu1.tell_all_course()
    
    tea1=OldboyTeacher('egon',18,'male',10)
    tea1.courses.append(python)
    # print(tea1.courses)
    tea1.tell_all_course()
    

    三大特性之二:多态

    多态与多态性

    '''
    1. 什么是多态
        多态指的是同一种/类事物的不同形态
    
    2. 为何要用多态
        多态性:在多态的背景下,可以在不用考虑对象具体类型的前提下而直接使用对象
        多态性的精髓:统一
    
    3. 如何用多态
    '''
    '''
    class Animal:
        def speak(self):
            pass
    
    class People(Animal):
        def shuo(self):
            print('say hello')
    
    class Dog(Animal):
        def jiao(self):
            print('汪汪汪')
    
    class Pig(Animal):
        def chang(self):
            print('哼哼哼')
    
    obj1=People()
    obj2=Dog()
    obj3=Pig()
    
    
    # obj1.speak()
    # obj2.speak()
    # obj3.speak()
    
    def speak(animal):
        animal.speak()
    
    speak(obj1)
    speak(obj2)
    speak(obj3)
    
    s1='hello'
    l1=[1,2,3]
    t1=(1,2)
    
    # changdu(s1)
    # size(l1)
    # kuangdu(t1)
    
    print(len(s1)) #s1.__len__()
    print(len(l1)) #l1.__len__()
    print(len(t1)) #t1.__len__()
    '''
    import abc
    
    class Animal(metaclass=abc.ABCMeta):
        @abc.abstractmethod
        def speak(self):
            pass
    
        @abc.abstractmethod
        def run(self):
            pass
    
    # Animal() # 父类只是用来建立规范的,不能用来实例化的,更无需实现内部的方法
    
    class People(Animal):
        def speak(self):
            print('say hello')
    
        def run(self):
            pass
    
    class Dog(Animal):
        def speak(self):
            print('汪汪汪')
    
        def run(self):
            pass
    
    class Pig(Animal):
        def speak(self):
            print('哼哼哼')
    
        def run(self):
            pass
    
    obj1=People()
    obj2=Dog()
    obj3=Pig()
    
    
    # python崇尚鸭子类型
    class Disk:
        def read(self):
            print('Disk read')
    
        def write(self):
            print('Disk write')
    
    
    class Memory:
        def read(self):
            print('Mem read')
    
        def write(self):
            print('Mem write')
    
    
    class Cpu:
        def read(self):
            print('Cpu read')
    
        def write(self):
            print('Cpu write')
    
    
    obj1=Disk()
    obj2=Memory()
    obj3=Cpu()
    
    obj1.read()
    obj2.read()
    obj3.read()
    

    三大特性之二:封装

    封装

    '''
    1. 什么是封装
        装:往容器/名称空间里存入名字
        封:代表将存放于名称空间中的名字给藏起来,这种隐藏对外不对内
    
    2. 为何要封装
        封数据属性:???
        封函数属性:???
    
    3. 如何封装
        在类内定义的属性前加__开头(没有__结果)
        总结:
            1. __开头的属性实现的隐藏仅仅只是一种语法意义上的变形,并不会真的限制类外部的访问
            2. 该变形操作只在类定义阶段检测语法时发生一次,类定义阶段之后新增的__开头的属性并不会变形
            3. 如果父类不想让子类覆盖自己的属性,可以在属性前加__开头
    '''
    class Foo:
        __x=111 # _Foo__x
        __y=222 # _Foo__y
    
        def __init__(self,name,age):
            self.__name=name
            self.__age=age
    
        def __func(self): #_Foo__func
            print('func')
    
        def get_info(self):
            print(self.__name,self.__age,self.__x) #print(self._Foo__name,self._Foo__age,self._Foo__x)
    
    # print(Foo.__x)
    # print(Foo.__func)
    # print(Foo.__dict__)
    # print(Foo._Foo__x)
    # print(Foo._Foo__y)
    # Foo.__z=333
    # print(Foo.__dict__)
    # print(Foo.__z)
    
    obj=Foo('egon',18)
    # print(obj.__dict__)
    # print(obj.__name)
    # print(obj.__age)
    # obj.get_info()
    
    obj.__sex='male'
    # print(obj.__dict__)
    # print(obj.__sex)
    
    # obj.get_info()
    # 1. __开头的属性到底如何实现的隐藏?
    # 2. 如何实现的对外隐藏,对内不隐藏
    
    class Foo:
        def __f1(self): #_Foo__f1
            print('Foo.f1')
    
        def f2(self):
            print('Foo.f2')
            self.__f1() #obj._Foo__f1()
    
    class Bar(Foo):
        def __f1(self): # _Bar__f1 (与上面的__f1就不一样了)
            print('Bar.f1')
    
    obj=Bar()
    # obj.f2()
    '''
    Foo.f2
    Foo.f1
    '''
    
    # 封装数据属性:将数据属性隐藏起来,类外就无法直接操作属性,需要类内开辟一个接口来外部的使用可以间接地操作属性,可以在接口内定义任意的控制逻辑,
    # 从而严格控制使用对属性的操作
    class People:
        def __init__(self,name,age):
            self.__name=name
            self.__age=age
    
        def tell_info(self): # 为了让外部能够访问到(这种访问是间接的,是提供给外部的)
            print('<name:%s age:%s>'  %(self.__name,self.__age))
    
        def set_info(self,name,age): # 为了让外部改数据(同上)
            if type(name) is not str:
                print('名字必须是str类型傻叉')
                return
            if type(age) is not int:
                print('年龄必须是int类型傻叉')
                return
            self.__name=name
            self.__age=age
    
    obj=People('egon',18)
    # obj.tell_info()
    # obj.set_info('EGON',19)
    # obj.set_info(123,19)
    obj.set_info('EGON','18')
    obj.tell_info()
    
    # 封装函数属性:隔离复杂度
    class ATM:
        def __card(self):
            print('插卡')
        def __auth(self):
            print('用户认证')
        def __input(self):
            print('输入取款金额')
        def __print_bill(self):
            print('打印账单')
        def __take_money(self):
            print('取款')
    
        def withdraw(self):
            self.__card()
            self.__auth()
            self.__input()
            self.__print_bill()
            self.__take_money()
    
    a=ATM()
    a.withdraw()
    

    property

    # property装饰器是用来将类内的函数属性伪装成数据属性
    class People:
        def __init__(self,name,weight,height):
            self.name=name
            self.weight=weight
            self.height=height
    
        @property
        def bmi(self):
            return self.weight / (self.height ** 2)
    
    obj=People('egon',80,1.83)
    obj.height=1.85
    obj.weight=75
    
    print(obj.bmi()) # 没用装饰器之前
    print(obj.bmi)  # 用过装饰器之后可以直接将bmi当做数据来看待
    
    # 了解....
    class People:
        def __init__(self,name):
            self.__name=name
    
        @property
        def name(self):
            return '<名字:%s>' %self.__name
    
        @name.setter #为对象修改属性,但在此之前要用property修饰过
        def name(self,obj):
            if type(obj) is not str:
                print('name必须为str类型')
                return
            self.__name=obj
    
        @name.deleter #删除属性操作
        def name(self):
            # print('不让删')
            del self.__name
    
    obj=People('egon')
    
    # print(obj.name)
    # obj.name='EGON' 
    # obj.name=123
    # print(obj.name)
    # del obj.name
    # print(obj.__dict__)
    
    # 另外一种写法
    class People:
        def __init__(self,name):
            self.__name=name
    
        def get_name(self):
            return '<名字:%s>' %self.__name
    
        def set_name(self,obj):
            if type(obj) is not str:
                print('name必须为str类型')
                return
            self.__name=obj
    
        def del_name(self):
            # print('不让删')
            del self.__name
    	#不推荐这种写法,建议用上面的写法
    	name=property(get_name,set_name,del_name)
    
    obj=People('egon')
    print(obj.name)
    obj.name='EGON'
    obj.name=123
    print(obj.name)
    del obj.name
    print(obj.__dict__)
    

    绑定方法与非绑定方法

    # 一: 绑定方法:绑定给谁就应该由谁来调用,谁来调用就会将谁当做第一个参数传入
    # 1. 绑定给对象的方法: 类中定义的函数默认就是绑定给对象的
    # 2. 绑定给类的方法: 为类中定义的函数加上一个装饰器classmethod
    
    # 二: 非绑定方法: 既不与类绑定,又不与对象绑定,意味着对象和类都可以来调用,无论谁来调用都是一个普通的函数,没有自动传值的效果
    class Foo:
        def f1(self):
            print(self)
    
        @classmethod
        def f2(cls):
            print(cls)
    
        @staticmethod
        def f3(x,y):
            print('f3',x+y)
    
    obj=Foo()
    print(obj.f1)
    obj.f1()
    
    print(Foo.f2)
    Foo.f2()
    print(obj.f2)
    obj.f2()
    
    print(Foo.f3)
    print(obj.f3)
    
    Foo.f3(1,2)
    obj.f3(3,4)
    
    # 应用
    import settings
    
    class MySql:
        def __init__(self, ip, port):
            self.id = self.create_id()
            self.ip = ip
            self.port = port
    
        def tell_info(self):
            print('<id:%s ip:%s port:%s>' % (self.id, self.ip, self.port))
    
        @classmethod #为类提供额外的实列化方式
        def from_conf(cls):
            return cls(settings.IP, settings.PORT)
    
        @staticmethod #既不需要传类也不需要传对象
        def create_id():
            import uuid
            return uuid.uuid4()
    
    # obj1=MySql('1.1.1.1',3306)
    # obj1.tell_info()
    obj2 = MySql.from_conf()
    obj2.tell_info()
    
    

    面向对象串讲

    '''
    1 类与对象
        对象是特征与技能的结合体,而类则是一些列对象相同特征与技能的结合
        对象本质是一个容器/名称空间:用来存放对象特有的属性
        类的本质也是一个容器/名称空间:用来存放对象相同的属性
    
        类有两种用途:
            1. 当容器去用
                类的数据属性
                类的函数属性
            2. 调用类的过程称为实例化,结果就是对象
                实例化时方式两件事:
                    1. 先产生一个空对象
                    2. 触发__init__(空对象,arg1,arg2,...)
    
    2 继承与派生
        1. 什么是继承
            继承是一种新建类的方式,新建的类称之为子类/派生类,被继承类称之为父类/超类/基类
    
            继承描述的是一种遗传的关系,特点:
                1. 子类可以遗传/重用父类的属性(减少代码冗余)
                2. 一个子类可以同时继承多个父类
                3. 在继承的背景下,类分为新式类与经典类
    
            子类如何重用父类属性?
            在继承背景下属性的查找顺序???
            新式类vs经典类
    
        2. 为何要用继承
            解决类与类之间代码冗余的问题
    
        3. 如何继承
            class Foo:
                pass
    
            class Bar(Foo):
                x=1
    
            obj=Bar()
    
        4. 在子类派生新方法中重用父类功能的两种方式:
            方式一:指名道姓地访问某一个类的函数
                特点:
                    1. 与继承无关
                    2. 没有自动传值的效果
            方式二:super(自己的类名,self)会得到一个特殊的对象,该对象专门用来访问"父类"中的属性,完全参照mro列表
                特点:
                    1. 严格依赖继承,完全参照mro列表
                    2. 有自动传值的效果
    
    3 组合
        1. 什么是组合
            组合指的是一个对象拥有某一个属性,该属性的值是来自于另外一个类的对象
            class OldboyStudent:
                pass
    
            class OldboyTeacher:
                pass
    
            class Course:
                pass
    
    
            stu=OLdboyStudent()
            tea=OLdboyTeacher()
    
            obj=Course()
    
            stu.attr=obj
            tea.attr=obj
    
        2. 为何要用组合
            解决类与类之间代码冗余的问题
    
    4 多态
        多态指的是同一种事物的多种形态,
        多态性指的是可以在不用考虑对象具体类型前提下而直接使用对象
        多态的精髓就是"统一"二字
    
        python崇尚鸭子类型
    
    5 封装
        装
        封
    '''
    class Foo:
        x=1
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def f1(self):
            print('run')
    
    # print(Foo.__dict__)
    obj=Foo('egon',18)
    # print(obj.__dict__)
    
    class A:
        def f1(self):
            print('A.f1')
            super().f2()
    
    class B:
        def f2(self):
            print('B.f2')
    
    class C(A,B):
        def f2(self):
            print('C.f2')
    
    obj=C()
    print(C.mro())
    obj.f1()
    '''
    A.f1
    '''
    
    class People:
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
    class Teacher(People):
        def __init__(self,name,age,sex,level):
            # People.__init__(self,name,age,sex)
            super().__init__(name,age,sex)
            self.level=level
    
    obj=Teacher('egon',18,'male',18)
    print(obj.__dict__)
    
  • 相关阅读:
    【GIS】Vue、Leaflet、highlightmarker、bouncemarker
    【PHP】xampp配置多个监听端口和不同的网站目录(转)
    【ArcGIS】栅格分析-问题之001(转)
    java登录央行征信网站
    登录中国人民银行征信中心
    爬取百度百科上中国所有城市的信息
    pycharm pro版本激活
    一种爬虫架构分享
    中国联通短信验证码
    中国联通通话记录、身份认证、上网记录等信息
  • 原文地址:https://www.cnblogs.com/chenwang-23/p/10946795.html
Copyright © 2020-2023  润新知