• 面向对象,绑定方法与异常处理(七)


    1.1 继承与派生

    1.1.1 什么是继承

        是一种新建类的方式,新建的类称为子类,子类会遗传父类的属性,可以减少代码冗余
        在python中,子类(派生类)可以继承一个或者多个父类(基类,超类)
     
    python中类的继承分为:单继承和多继承
    class Parent1:    #定义父类
    
        pass
    
     
    
    class Parent2(object): #定义父类
    
        pass
    
     
    
    class Sub1(Parent1):  ##单继承,基类是Parent1,派生类是Sub1
    
        pass
    
     
    
    class Sub2(Parent1,Parent2): #python支持多继承,用逗号分隔开多个继承的类
    
        pass
     
    查看继承
    print(Sub1.__bases__)   #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
    
    print(Sub2.__bases__)
    
    提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
    print(Parent1.__bases__)
    
    print(Parent2.__bases__)
     
    在Python2中类分为两种:
    1、经典类:指的就是没有继承object类的类,以及该类的子类
    2、新式类:指的就是继承object类的类,以及该类的子类
    在Python3中统一都为新式类
    class OldboyPeople:
    
        school = 'Oldboy'
    
     
    
        def __init__(self, name, age, sex):
    
            self.name = name
    
            self.age = age
    
            self.sex = sex
    
     
    
        def tell_info(self):
    
            print('<名字:%s 年龄:%s 性别:%s>' %(self.name,self.age,self.sex))
    
     
    
    class OldboyStudent(OldboyPeople):
    
        def learn(self):
    
            print('%s is learning' %self.name)
    
     
    
        def tell_info(self):
    
            print('我是学生:',end='')
    
            print('<名字:%s 年龄:%s 性别:%s>' % (self.name, self.age, self.sex))
    
     
    
    class OldboyTeacher(OldboyPeople):
    
        def teach(self):
    
            print('%s is teaching' %self.name)
    
     
    
        def tell_info(self):
    
            print('我是老师:',end='')
    
            print('<名字:%s 年龄:%s 性别:%s>' % (self.name, self.age, self.sex))
    
     
    
    stu1=OldboyStudent('牛榴弹',18,'male')
    
    teacher1=OldboyTeacher('egon',18,'male')
    
     
    
    print(stu1.__dict__)
    
    print(stu1.school)
    
    print(stu1.x)
    
     
    
    stu1.tell_info()
    
    teacher1.tell_info() 
     
     
    属性查找
    继承描述的是子类与父类之间的关系,是一种什么是什么的关系。要找出这种关系,必须先抽象再继承
     
    抽象即抽取类似或者说比较像的部分。
    class Foo:
    
        def f1(self):
    
            print('Foo.f1')
    
     
    
        def f2(self): #self=obj
    
            print('Foo.f2')
    
            self.f1() #obj.f1()
    
     
    
    class Bar(Foo):
    
        def f1(self):
    
            print('Bar.f1')
    
     
    
    obj=Bar()
    
    print(obj.__dict__)
    
    obj.f2()

    1.2 子类重用父类方法part1:

    在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时

    我们不可能从头开始写一个类B,这就用到了类的继承的概念。

    通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用

    class OldboyPeople:
    
        school = 'Oldboy'
    
     
    
        def __init__(self, name, age, sex):
    
            self.name = name
    
            self.age = age
    
            self.sex = sex
    
     
    
        def tell_info(self):
    
            print('<名字:%s 年龄:%s 性别:%s>' %(self.name,self.age,self.sex))
    
     
    
    class OldboyStudent(OldboyPeople):
    
        def learn(self):
    
            print('%s is learning' %self.name)
    
     
    
        def tell_info(self):
    
            print('我是学生:',end='')
    
            # self.tell_info() #stu1.tell_info()
    
            OldboyPeople.tell_info(self)
    
     
    
    stu1=OldboyStudent('牛榴弹',18,'male')
    
    stu1.tell_info()
    
     
    class OldboyPeople:
    
        school = 'Oldboy'
    
     
    
        def __init__(self, name, age, sex):
    
            self.name = name
    
            self.age = age
    
            self.sex = sex
    
     
    
        def tell_info(self):
    
            print('<名字:%s 年龄:%s 性别:%s>' %(self.name,self.age,self.sex))
    
     
    
    class OldboyStudent(OldboyPeople):
    
        def __init__(self,name,age,sex,course,stu_id):
    
            # self.name=name
    
            # self.age=age
    
            # self.sex=sex
    
            OldboyPeople.__init__(self,name,age,sex)
    
            self.course=course
    
            self.stu_id=stu_id
    
     
    
        def learn(self):
    
            print('%s is learning' %self.name)
    
     
    
        def tell_info(self):
    
            print('我是学生:',end='')
    
            # self.tell_info() #stu1.tell_info()
    
            OldboyPeople.tell_info(self)
    
     
    
    stu1=OldboyStudent('牛榴弹',18,'male','Python',1)
    
    stu1.tell_info()
    
     

    1.3 组合

    组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合

    class OldboyPeople:
    
        school = 'Oldboy'
    
     
    
        def __init__(self, name, age, sex):
    
            self.name = name
    
            self.age = age
    
            self.sex = sex
    
     
    
        def tell_info(self):
    
            print('<名字:%s 年龄:%s 性别:%s>' %(self.name,self.age,self.sex))
    
     
    
    class OldboyStudent(OldboyPeople):
    
        def __init__(self,name,age,sex,course,stu_id,year,mon,day):
    
            OldboyPeople.__init__(self,name,age,sex)
    
            self.course=course
    
            self.stu_id=stu_id
    
     
    
            self.year=year
    
            self.mon=mon
    
            self.day=day
    
     
    
        def learn(self):
    
            print('%s is learning' %self.name)
    
     
    
        def tell_info(self):
    
            print('我是学生:',end='')
    
            # self.tell_info() #stu1.tell_info()
    
            OldboyPeople.tell_info(self)
    
     
    
        def tell_birth(self):
    
            print('出生日期是:<%s-%s-%s>' %(self.year,self.mon,self.day))
    
     
    
    class OldboyTeacher(OldboyPeople):
    
        def __init__(self, name, age, sex, level,salary,year,mon,day):
    
            OldboyPeople.__init__(self, name, age, sex)
    
            self.level=level
    
            self.salary=salary
    
     
    
            self.year=year
    
            self.mon=mon
    
            self.day=day
    
     
    
        def tell_birth(self):
    
            print('出生日期是:<%s-%s-%s>' %(self.year,self.mon,self.day))
    
     
    
        def teach(self):
    
            print('%s is teaching' % self.name)
    
     
    
        def tell_info(self):
    
            print('我是老师:', end='')
    
            OldboyPeople.tell_info(self)
    
     
    
     
    
    stu1=OldboyStudent('牛榴弹',18,'male','Python',1,1983,3,11)
    
    teacher1=OldboyTeacher('啊狗',18,'female',10,4000,1990,2,17)
    
     
    
     
    
    stu1.tell_birth()
    
    teacher1.tell_birth()

    组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同,

    1.继承的方式

    通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。

    当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人

    2.组合的方式

    用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...

    class OldboyPeople:
    
        school = 'Oldboy'
    
     
    
        def __init__(self, name, age, sex):
    
            self.name = name
    
            self.age = age
    
            self.sex = sex
    
     
    
        def tell_info(self):
    
            print('<名字:%s 年龄:%s 性别:%s>' % (self.name, self.age, self.sex))
    
     
    
     
    
    class OldboyStudent(OldboyPeople):
    
        def __init__(self, name, age, sex, course, stu_id,):
    
            OldboyPeople.__init__(self, name, age, sex)
    
            self.course = course
    
            self.stu_id = stu_id
    
     
    
     
    
     
    
        def learn(self):
    
            print('%s is learning' % self.name)
    
     
    
        def tell_info(self):
    
            print('我是学生:', end='')
    
            # self.tell_info() #stu1.tell_info()
    
            OldboyPeople.tell_info(self)
    
     
    
    class OldboyTeacher(OldboyPeople):
    
        def __init__(self, name, age, sex, level, salary):
    
            OldboyPeople.__init__(self, name, age, sex)
    
            self.level = level
    
            self.salary = salary
    
     
    
        def teach(self):
    
            print('%s is teaching' % self.name)
    
     
    
        def tell_info(self):
    
            print('我是老师:', end='')
    
            OldboyPeople.tell_info(self)
    
     
    
    class Date:
    
        def __init__(self,year,mon,day):
    
            self.year = year
    
            self.mon = mon
    
            self.day = day
    
     
    
        def tell_birth(self):
    
            print('出生日期是:<%s-%s-%s>' % (self.year, self.mon, self.day))
    
     
    
    stu1 = OldboyStudent('牛榴弹', 18, 'male', 'Python', 1,)
    
    date_obj1=Date(1983, 3, 11)
    
    stu1.birth=date_obj1
    
     
    
     
    
    teacher1 = OldboyTeacher('啊狗', 18, 'female', 10, 4000)
    
    date_obj2=Date( 1990, 2, 17)
    
    teacher1.birth=date_obj2
    
     
    
     
    
    # print(stu1.birth)
    
    # print(teacher1.birth)
    
     
    
    stu1.birth.tell_birth() #date_obj1.tell_birth()
    
    teacher1.birth.tell_birth()
    
     

     

    class OldboyPeople:
    
        school = 'Oldboy'
    
     
    
        def __init__(self, name, age, sex,date_obj):
    
            self.name = name
    
            self.age = age
    
            self.sex = sex
    
            self.birth = date_obj
    
     
    
        def tell_info(self):
    
            print('<名字:%s 年龄:%s 性别:%s>' % (self.name, self.age, self.sex))
    
     
    
    class OldboyStudent(OldboyPeople):
    
        def __init__(self, name, age, sex, course, stu_id,date_obj):
    
            OldboyPeople.__init__(self, name, age, sex,date_obj)
    
            self.course = course
    
            self.stu_id = stu_id
    
     
    
     
    
        def learn(self):
    
            print('%s is learning' % self.name)
    
     
    
        def tell_info(self):
    
            print('我是学生:', end='')
    
            # self.tell_info() #stu1.tell_info()
    
            OldboyPeople.tell_info(self)
    
     
    
    class OldboyTeacher(OldboyPeople):
    
        def __init__(self, name, age, sex, level, salary,date_obj):
    
            OldboyPeople.__init__(self, name, age, sex,date_obj)
    
            self.level = level
    
            self.salary = salary
    
     
    
        def teach(self):
    
            print('%s is teaching' % self.name)
    
     
    
        def tell_info(self):
    
            print('我是老师:', end='')
    
            OldboyPeople.tell_info(self)
    
     
    
    class OldboySale(OldboyPeople):
    
        def __init__(self,name,age,sex,kpi,date_obj):
    
            OldboyPeople.__init__(self,name,age,sex,date_obj)
    
            self.kpi=kpi
    
     
    
        def tell_info(self):
    
            print('我是销售: ',end='')
    
            OldboyPeople.tell_info(self)
    
     
    
    class Date:
    
        def __init__(self,year,mon,day):
    
            self.year = year
    
            self.mon = mon
    
            self.day = day
    
     
    
        def tell_birth(self):
    
            print('出生日期是:<%s-%s-%s>' % (self.year, self.mon, self.day))
    
     
    
    date_obj1=Date(1983, 3, 11)
    
    sale1=OldboySale('歪歪',38,'male',7.3,date_obj1)
    
    # sale1.birth=date_obj1
    
    # sale1.tell_info()
    
     
    
    sale1.birth.tell_birth()
    
     
    
     
    class OldboyPeople:
    
        school = 'Oldboy'
    
     
    
        def __init__(self, name, age, sex,date_obj):
    
            self.name = name
    
            self.age = age
    
            self.sex = sex
    
            self.birth = date_obj
    
     
    
        def tell_info(self):
    
            print('<名字:%s 年龄:%s 性别:%s>' % (self.name, self.age, self.sex))
    
     
    
    class OldboyStudent(OldboyPeople):
    
        def __init__(self, name, age, sex, stu_id,date_obj):
    
            OldboyPeople.__init__(self, name, age, sex,date_obj)
    
            self.courses=[]
    
            self.stu_id = stu_id
    
     
    
     
    
        def learn(self):
    
            print('%s is learning' % self.name)
    
     
    
        def tell_info(self):
    
            print('我是学生:', end='')
    
            # self.tell_info() #stu1.tell_info()
    
            OldboyPeople.tell_info(self)
    
     
    
    class OldboyTeacher(OldboyPeople):
    
        def __init__(self, name, age, sex, level, salary,date_obj):
    
            OldboyPeople.__init__(self, name, age, sex,date_obj)
    
            self.level = level
    
            self.salary = salary
    
            self.courses=[]
    
     
    
        def teach(self):
    
            print('%s is teaching' % self.name)
    
     
    
        def tell_info(self):
    
            print('我是老师:', end='')
    
            OldboyPeople.tell_info(self)
    
     
    
    class OldboySale(OldboyPeople):
    
        def __init__(self,name,age,sex,kpi,date_obj):
    
            OldboyPeople.__init__(self,name,age,sex,date_obj)
    
            self.kpi=kpi
    
     
    
        def tell_info(self):
    
            print('我是销售: ',end='')
    
            OldboyPeople.tell_info(self)
    
     
    
    class Date:
    
        def __init__(self,year,mon,day):
    
            self.year = year
    
            self.mon = mon
    
            self.day = day
    
     
    
        def tell_birth(self):
    
            print('出生日期是:<%s-%s-%s>' % (self.year, self.mon, self.day))
    
     
    
    class Course:
    
        def __init__(self,name,price,period):
    
            self.name=name
    
            self.price=price
    
            self.period=period
    
     
    
        def tell_info(self):
    
            print('课程详细信息:<%s,%s,%s>' %(self.name,self.price,self.period))
    
     
    
    Python=Course('python自动化养猪',3000,'3mon')
    
    Linux=Course('大数据分析-linux',3000,'3mon')
    
    date_obj=Date(1993,3,13)
    
     
    
    teacher1=OldboyTeacher('egon',18,'male',100,3000,date_obj)
    
    teacher1.courses.append(Python)
    
    teacher1.courses.append(Linux)
    
     
    
    # print(teacher1.courses)
    
    for course in teacher1.courses:
    
        course.tell_info()
    
     
    
     
    
    stu1=OldboyStudent('xxxx',28,'female',1,date_obj)
    
    # print(stu1.courses)
    
     
    
    stu1.courses.append(Python)
    
    stu1.courses.append(Linux)
    
     
    
    print(stu1.courses)
    
     

     

    1.4 抽象类

    1.4.1 什么是抽象类

    与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

    为什么要有抽象类

        如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。

      比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。

        从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

      从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案

    import abc
    
     
    
    class Animal(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod
    
        def eat(self):
    
            pass
    
     
    
        @abc.abstractmethod
    
        def run(self):
    
            pass
    
     
    
     
    
    class People(Animal):
    
        def eat(self):
    
            pass
    
        def run(self):
    
            pass
    
     
    
    class Pig(Animal):
    
        def eat(self):
    
            pass
    
        def run(self):
    
            pass
    
     
    
    peo1=People()
    
    pig1=Pig()

     

    1.4.2 抽象类与接口

    抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

    抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计

    import abc
    
     
    
    class File(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod
    
        def read(self):
    
            pass
    
     
    
        @abc.abstractmethod
    
        def write(self):
    
            pass
    
     
    
    class Disk(File):
    
        def read(self):
    
            print('disk read')
    
     
    
        def write(self):
    
            print('disk write')
    
     
    
     
    
    class Process(File):
    
        def read(self):
    
            print('Process read')
    
     
    
        def write(self):
    
            print('Process write')
    
     
    
    d=Disk()
    
    p=Process()
    
     
    
    d.read()
    
    d.write()
    
     
    
    p.read()
    
    p.write()
    
     
    
     

    1.5 继承的实现原理

    继承顺序

    在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D)

    如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性

    如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先

     

    图1-1  

     

    图1-2  

    class A(object):
    
        # def test(self):
    
        #     print('from A')
    
        pass
    
     
    
    class B(A):
    
        # def test(self):
    
        #     print('from B')
    
        pass
    
     
    
    class C(A):
    
        # def test(self):
    
        #     print('from C')
    
        pass
    
    class D(B):
    
        # def test(self):
    
        #     print('from D')
    
        pass
    
     
    
    class E(C):
    
        # def test(self):
    
        #     print('from E')
    
        pass
    
    class F(D,E):
    
        # def test(self):
    
        #     print('from F')
    
        pass
    
     
    
    f1=F()
    
    print(F.mro())
    
    # f1.test()
    
     
    
     

    1.6 子类重用父类的方法part2

    1.6.1 方法一:指名道姓,即父类名.父类方法()

    class OldboyPeople:
    
        school = 'Oldboy'
    
     
    
        def __init__(self, name, age, sex):
    
            self.name = name
    
            self.age = age
    
            self.sex = sex
    
     
    
        def tell_info(self):
    
            print('<名字:%s 年龄:%s 性别:%s>' %(self.name,self.age,self.sex))
    
     
    
    class OldboyStudent(OldboyPeople):
    
        def __init__(self,name,age,sex,course):
    
            # OldboyPeople.__init__(self,name,age,sex)
    
            super(OldboyStudent,self).__init__(name,age,sex)
    
            self.course=course
    
     
    
        def tell_info(self):
    
            print('我是学生: ',end='')
    
            # OldboyPeople.tell_info(self)
    
            super(OldboyStudent,self).tell_info()
    
     
    
     
    
    stu1=OldboyStudent('egon',18,'male','python')
    
     
    
    # print(stu1.name,stu1.age,stu1.sex,stu1.course)
    
    stu1.tell_info()

    1.6.2 方法二:super()

    class Foo:
    
        def f2(self):
    
            print('====?>')
    
     
    
        def f1(self):
    
            print('Foo.f1')
    
            # super().f2()
    
            Foo.f2(123)
    
    class Bar:
    
        def f2(self):
    
            print('Bar f2')
    
     
    
    class Sub(Foo,Bar):
    
        pass
    
     
    
    s=Sub()
    
    # print(Sub.mro())
    
    # [<class '__main__.Sub'>,
    
    # <class '__main__.Foo'>,
    
    # <class '__main__.Bar'>,
    
    #  <class 'object'>]
    
     
    
    s.f1()

    强调:二者使用哪一种都可以,但最好不要混合使用

    即使没有直接继承关系,super仍然会按照mro继续往后查找

    1.6.3 指名道姓与super()的区别

    当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)

    1.7 多态与多态性

    1.7.1 多态:同一种事物的多种形态

    import abc
    
     
    
    class Animal(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod
    
        def speak(self):
    
            pass
    
     
    
    class Pig(Animal):
    
        def speak(self):
    
            print('哼哼')
    
     
    
    class Dog(Animal):
    
        def speak(self):
    
            print('汪汪')
    
     
    
    class People(Animal):
    
        def speak(self):
    
            print('say hello')
    
     
    
     
    
     
    
    people1=People()
    
    dog1=Dog()
    
    pig1=Pig()

     

    1.7.2 多态性:指的是在不考虑对象具体类型的情况下,直接使用对象(对象的方法)

    people1.speak()
    
    dog1.speak()
    
    pig1.speak()
    
     
    
    def talk(obj):
    
        obj.speak()
    
     
    
    talk(people1) #people1.speak()
    
    talk(dog1)
    
    talk(pig1)
    
     
    
     
    
    list,str,tuple
    
    l=list([1,2,3])
    
    s=str('hello')
    
    t=tuple((1,'a',4,'b','c'))
    
     
    
    l.__len__()
    
    s.__len__()
    
    t.__len__()
    
     
    
    print(len(l))
    
    print(len(s))
    
    print(len(t))
    
     

    多态性是指在不考虑实例类型的情况下使用实例

    多态:同一种事物的多种形态

    1.7.3 多态性分为静态多态性和动态多态性

      静态多态性:如任何类型都可以用运算符+进行运算

      动态多态性:

    import abc
    
     
    
    class Pig:
    
        def speak(self):
    
            print('哼哼')
    
     
    
    class Dog:
    
        def speak(self):
    
            print('汪汪')
    
     
    
    class People:
    
        def speak(self):
    
            print('say hello')
    
     
    
    class Radio:
    
        def speak(self):
    
            print('radio speak')
    
     
    
     
    
    people1=People()
    
    dog1=Dog()
    
    pig1=Pig()
    
     

    1.7.4 为什么要用多态性

    其实大家从上面多态性的例子可以看出,我们并没有增加什么新的知识,也就是说python本身就是支持多态性的,这么做的好处是什么呢?

    1.增加了程序的灵活性

      以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)

    2.增加了程序额可扩展性

      通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用  

     

    import abc
    
     
    
    class Disk:
    
        def read(self):
    
            print('disk read')
    
     
    
        def write(self):
    
            print('disk write')
    
     
    
     
    
    class Process:
    
        def read(self):
    
            print('Process read')
    
     
    
        def write(self):
    
            print('Process write')
    
      

    1.8 封装之如何隐藏

    1.8.1 封装:

    1、__开头的属性只是一种语法意义上的变形,并不会真的限制外部的访问

    2、这种变形只在类定义阶段发送一次,类定义之后再新增的__开头的属性不会变形

    3、这种隐藏只对外不对内,因为类内部定义的属性在类定义阶段统一发生变形

    先看如何隐藏

    在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)

    class Foo:
    
        __N=1 #_Foo__N=1
    
        def __init__(self,x,y):
    
            self.x=x
    
            self.__y=y #self._Foo__y=y
    
     
    
        def __f1(self): #_Foo__f1
    
            print('f1')
    
     
    
        def f2(self):
    
            print(self.__N,self.__y) #print(self._Foo__N,self._Foo__y)
    
     
    
    print(Foo.__N)
    
    print(Foo.__f1)
    
    print(Foo.__dict__)
    
    print(Foo._Foo__N)
    
    print(Foo._Foo__f1)
    
     
    
    obj=Foo(1,2)
    
    print(obj.__dict__)
    
    print(obj._Foo__y)
    
     
    
    Foo.__M=2
    
    print(Foo.__dict__)
    
    print(Foo.__M)
    
     
    
    obj=Foo(1,2)
    
    print(obj.__dict__)
    
    obj.__z=3
    
    print(obj.__dict__)
    
    print(obj.__z)
    
     
    
    obj=Foo(1,2)
    
    obj.f2()
    
    print(obj.__N)

    这种变形需要注意的问题是:

    1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形,主要用来限制外部的直接访问。

    2.变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形

    3.继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

    class Foo:
    
        def __f1(self): #_Foo__f1
    
            print('Foo.f1')
    
     
    
        def f2(self):
    
            print('Foo.f2')
    
            self.__f1() #b._Foo__f1()
    
     
    
    class Bar(Foo):
    
        def __f1(self): #_Bar__f1
    
            print('Bar.f1')
    
     
    
     
    
    b=Bar()
    
    b.f2()
    
     
    
     

    1.9 封装之真正意义

    封装数据属性的目的:外部无法直接访问数据属性,类内部开放接口,然后可以在接口内严格控制对属性的增删改查操作

    class People:
    
        def __init__(self,name,age):
    
            # self.__name=name
    
            # self.__age=age
    
            self.set_info(name,age)
    
     
    
        def tell_info(self):
    
            print("姓名:<%s> 年龄:<%s>" %(self.__name,self.__age))
    
     
    
        def set_info(self,name,age):
    
            if type(name) is not str:
    
                raise TypeError('name must be str')
    
            if type(age) is not int:
    
                raise TypeError('age must be int')
    
     
    
            self.__name=name
    
            self.__age=age
    
     
    
    p=People('egon',18)
    
     
    
    # print(p.__name,p.__age)
    
    # p.tell_info()
    
     
    
    # p.set_info('EGON',20)
    
    p.set_info(3537,20)
    
    p.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()
    
     

     

    1.10 封装之property

    1.10.1 什么是特性property

    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 People:
    
        def __init__(self,name,age,height,weight):
    
            self.name=name
    
            self.age=age
    
            self.height=height
    
            self.weight=weight
    
     
    
        @property
    
        def bmi(self):
    
            return self.weight / (self.height ** 2)
    
     
    
    egon=People('egon',18,1.80,75)
    
    egon.height=1.82
    
    # print(egon.bmi())
    
     
    
    print(egon.bmi)
    
     

     

    1.10.2 为什么要用property

    将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

    class People:
    
        def __init__(self,name,):
    
            self.__name=name
    
     
    
        @property
    
        def name(self):
    
            return self.__name
    
     
    
        @name.setter
    
        def name(self,obj):
    
            if type(obj) is not str:
    
                raise TypeError('name must be str')
    
            self.__name=obj
    
     
    
        @name.deleter
    
        def name(self):
    
            # del self.__name
    
            raise PermissionError('不让删')
    
     
    
    egon=People('egon')
    
     
    
    # print(egon.name)
    
     
    
    # egon.name='EGON'
    
    # egon.name=35357
    
    # print(egon.name)
    
     
    
    del egon.name
    
     
    
    # print(egon.name)

     

    封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。

    1.11 绑定方法与非绑定方法

    一:绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入):

        1. 绑定到类的方法:用classmethod装饰器装饰的方法。

                    为类量身定制

                    类.boud_method(),自动将类当作第一个参数传入

                  (其实对象也可调用,但仍将类当作第一个参数传入)

        2. 绑定到对象的方法:没有被任何装饰器装饰的方法。

                   为对象量身定制

                   对象.boud_method(),自动将对象当作第一个参数传入

                 (属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值那么一说)

    二:非绑定方法:用staticmethod装饰器装饰的方法

            1. 不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说。就是一个普通工具而已

        注意:与绑定到对象方法区分开,在类中直接定义的函数,没有被任何装饰器装饰的,都是绑定到对象的方法,可不是普通函数,对象调用该方法会自动传值,而staticmethod装饰的方法,不管谁来调用,都没有自动传值一说

    1.11.1 绑定方法

    绑定给对象的方法(略)

    绑定给类的方法(classmethod)

    classmehtod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数(即便是对象来调用也会将类当作第一个参数传入),python为我们内置了函数classmethod来把类中的函数定义成类方法

    import settings
    
    import hashlib
    
    import time
    
     
    
    class MySQL:
    
        def __init__(self,host,port):
    
            self.host=host
    
            self.port=port
    
     
    
        def func(self):
    
            print('%s 说:你好啊我的天' %self.name)
    
     
    
        @classmethod
    
        def from_conf(cls):
    
            return cls(settings.HOST,settings.PORT)
    
     
    
        @staticmethod
    
        def create_id(n):
    
            m=hashlib.md5()
    
            m.update(str(time.clock()+n).encode('utf-8'))
    
            return m.hexdigest()
    
    # conn=MySQL('127.0.0.1',3306)
    
     
    #绑定方法:绑定给谁就应该由谁来调用,谁来调用就会把谁当做第一个参数自动传入
     

    1.11.2 非绑定方法

    在类内部用staticmethod装饰的函数即非绑定方法,就是普通函数
    statimethod不与类或对象绑定,谁都可以调用,没有自动传值效果
    conn=MySQL.from_conf()
    
    # print(conn.host,conn.port)
    
     
    
     
    
    print(MySQL.create_id(1))
    
    print(conn.create_id(2))
    
     

    1.12 内置函数补充

    l=list([])
    
     
    
    print(type(l) is list)
    
    print(isinstance(l,list))
    
     
    
    class Foo:
    
        pass
    
     
    
    class Bar(Foo):
    
        pass
    
     
    
    print(issubclass(Bar,Foo))
    
     
    
     

    1.13 反射

    1.13.1 什么是反射

    反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

    class Foo:
    
        def __init__(self,name):
    
            self.name=name
    
     
    
        def f1(self):
    
            print('===>f1')
    
     
    
    obj=Foo('egon')
    
    obj.name #obj.__dict__['name']

    1.13.2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

    四个可以实现自省的函数

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

    hasattr

    print(hasattr(obj,'name')) #obj.name
    
    print(hasattr(obj,'f1'))#obj.f1

    getattr

    if hasattr(obj,'f1'):
    
        f=getattr(obj,'f1') #f=obj.f1
    
        f()
    
    print(getattr(obj,'xxx',None))
    
     

    setattr

    obj.x=1
    
    setattr(obj,'x',1)
    
    print(obj.__dict__)
    
     

    delattr

    del obj.name
    
    delattr(obj,'name')
    
    print(obj.__dict__)

    导入其他模块,利用反射查找该模块是否存在某个方法

    class FtpClient:
    
        def __init__(self,host,port):
    
            self.host=host
    
            self.port=port
    
            self.conn='xxx'
    
     
    
        def interactie(self):
    
            while True:
    
                cmd=input('>>: ').strip()
    
                if not cmd:continue
    
                cmd_l=cmd.split()
    
                print(cmd_l)
    
                if hasattr(self,cmd_l[0]):
    
                    func=getattr(self,cmd_l[0])
    
                    func(cmd_l)
    
     
    
        def get(self,cmd_l):
    
            print('geting...',cmd_l)
    
     
    
        def put(self,cmd_l):
    
            print('putting....',cmd_l)
    
     
    
    client=FtpClient('1.1.1.1',23)
    
    client.interactie()

    1.14 类的内置方法

    __str__

    l=list([1,2,3,4])
    
    print(l)
    
     
    
    class People:
    
        def __init__(self,name,age):
    
            self.name=name
    
            self.age=age
        def __str__(self):
    
            return '<name:%s age:%s>' %(self.name,self.age)
    
     
    
    egon=People('egon',18)
    
    print(egon) #print(egon.__str__())
    
     

     

    注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__

    __del__

    f=open('a.txt','w',encoding='utf-8')
    
    f.read()
    
    f.close()
    
     

     

    class Foo:
    
        def __del__(self):
    
            print('del---->')
    
     
    
    obj=Foo()
    
    del obj
    
    # print('主')

    setting.py

    HOST='10.10.10.9'
    
    PORT=3306
    class Mysql:
    
        def __init__(self,host,port):
    
            self.host=host
    
            self.port=port
    
            self.conn=Connect(host,port)
    
     
    
        def __del__(self):
    
            self.conn.close()
    
     
    
    m=Mysql('1.1.1.1',3306)
    
    m.conn.execute('select * from db.user;')

    1.15 异常处理

    1.15.1 什么是异常

    异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序的运行也随之终止),在python中,错误触发的异常如下

    而错误分成两种

    1.语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正) 

    2.逻辑错误

    # x=
    
     
    
    raise TypeError('xxxx')

    为了保证程序的健壮性与容错性,即在遇到错误时程序不会崩溃,我们需要对异常进行处理,

    如果错误发生的条件是可预知的,我们需要用if进行处理:在错误发生之前进行预防

    #基本语法为

    try:
    
        被检测的代码块
    
    except 异常类型:
    
        try中一旦检测到异常,就执行这个位置的逻辑
    
    #举例
    
    try:
    
        f=open('a.txt')
    
        g=(line.strip() for line in f)
    
        print(next(g))
    
        print(next(g))
    
        print(next(g))
    
        print(next(g))
    
        print(next(g))
    
    except StopIteration:
    
        f.close()
    
     
  • 相关阅读:
    手把手带你玩转 DialogFragment
    紧张的去京东面试7,没想到可以成功拿下offer
    这个有点强,MySQL常用优化指南及大表优化思路(值得收藏)
    Java程序员两年经验斩获头条 Offer,技术杠杠的
    为什么大家都说 SELECT * 效率低
    Java程序员想要靠外包刷题,结果却大跌眼镜,心态都崩了
    一次请求在SpringMVC核心执行流程
    工作三年经验,一年内我靠这份javaBAT进阶面试题从13K到大厂25K
    用了这么久的数据库连接池,你知道原理吗?
    poj 3295 Tautology(栈)
  • 原文地址:https://www.cnblogs.com/x-y-j/p/8342779.html
Copyright © 2020-2023  润新知