zoukankan      html  css  js  c++  java
  • 面向对象

    面向过程编程
    核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么然后干什么。。。
    基于该思想编写程序好比在设计一条流水线,是一种机械式的思维方式

    优点:复杂的问题流程化、进而简单化
    缺点:扩展性差

    面向对象编程

    核心对象二字,对象是特征与技能的结合体
    基于该思想编写程序就好比是在创造一个世界,你就是这个世界的上帝,是一种上帝式的思维方式

    优点:可扩展性强
    缺点:编程的复杂度要高于面向过程

    类:

    种类、分类、类别

    对象是特征与技能的结合体,类是一系列对象相似的特征与技能的结合体
    强调:站的角度不同,总结出的类是截然不同的

    在现实世界中:先有的一个个具体存在的对象,然后随着人类文明的发展才了分类的概念
    在程序中:必须先定义类,后调用类来产生对象

    #1、先定义类
    class OldboyStudent:
        school='oldboy'
    
        def choose_course(self):
            print('is choosing course')
    
    #强调:类定义阶段会立刻执行类体代码,会产生类的名称空间,将类体代码执行过程中产生的名字都丢进去
    # print(OldboyStudent.__dict__)
    # 类本质就是一个名称空间/容器,从类的名称空间中增/删/改/查名字
    # python为我们提供专门访问属性(名称空间中的名字)的语法,点后的都是属性
    # OldboyStudent.school #OldboyStudent.__dict__['school']
    # OldboyStudent.x=1 #OldboyStudent.__dict__['x']=1
    # OldboyStudent.school='Oldboy' #OldboyStudent.__dict__['school']='Oldboy'
    # del OldboyStudent.x #del OldboyStudent.__dict__['x']
    
    # 类中定义的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数而已,意味着需要完全遵循函数的参数规则,该传几个值就传几个
    # OldboyStudent.choose_course(123)
    
    #2、后调用类产生对象,调用类的过程称之为实例化,实例化的结果称为类的一个实例或者对象
    stu1=OldboyStudent()
    stu2=OldboyStudent()
    stu3=OldboyStudent()
    # print(stu1)
    # print(stu2)
    # print(stu3)
    
    # print(OldboyStudent.school)
    # OldboyStudent.school='OLDBOY'
    # print(stu1.school)
    # print(stu2.school)
    # print(stu3.school)

    对象初始化自己属性

    '''
    # 例1
    class OldboyStudent:
        school='oldboy'
    
        def choose_course(self):
            print('is choosing course')
    
    stu1=OldboyStudent()
    stu2=OldboyStudent()
    stu3=OldboyStudent()
    
    #对象本质也就是一个名称空间而已,对象名称空间是用存放对象自己独有的名字/属性,而
    #类中存放的是对象们共有的属性
    # print(stu1.__dict__)
    # print(stu2.__dict__)
    # print(stu3.__dict__)
    
    stu1.name='耗哥'
    stu1.age=18
    stu1.sex='male'
    # print(stu1.name,stu1.age,stu1.sex)
    # print(stu1.__dict__)
    
    stu2.name='猪哥'
    stu2.age=17
    stu2.sex='male'
    
    stu3.name='帅翔'
    stu3.age=19
    stu3.sex='female'
    
    
    # 例2
    class OldboyStudent:
        school='oldboy'
    
        def choose_course(self):
            print('is choosing course')
    
    stu1=OldboyStudent()
    stu2=OldboyStudent()
    stu3=OldboyStudent()
    
    def init(obj,x,y,z):
        obj.name=x
        obj.age=y
        obj.sex=z
    
    # stu1.name='耗哥'
    # stu1.age=18
    # stu1.sex='male'
    init(stu1,'耗哥',18,'male')
    
    # stu2.name='猪哥'
    # stu2.age=17
    # stu2.sex='male'
    init(stu2,'诸哥',17,'male')
    
    # stu3.name='帅翔'
    # stu3.age=19
    # stu3.sex='female'
    init(stu3,'帅翔',19,'female')
    
    
    print(stu1.__dict__)
    print(stu2.__dict__)
    print(stu3.__dict__)
    '''
    
    
    class OldboyStudent:
        school='oldboy'
    
    
        def __init__(obj, x, y, z): #会在调用类时自动触发
            obj.name = x #stu1.name='耗哥'
            obj.age = y  #stu1.age=18
            obj.sex = z #stu1.sex='male'
    
        def choose_course(self):
            print('is choosing course')
    
    #调用类时发生两件事
    #1、创造一个空对象stu1
    #2、自动触发类中__init__功能的执行,将stu1以及调用类括号内的参数一同传入
    stu1=OldboyStudent('耗哥',18,'male') #OldboyStudent.__init__(stu1,'耗哥',18,'male')
    stu2=OldboyStudent('猪哥',17,'male')
    stu3=OldboyStudent('帅翔',19,'female')
    
    
    print(stu1.__dict__)
    print(stu2.__dict__)
    print(stu3.__dict__)

    属性查找

    class OldboyStudent:
        school='oldboy'
        count=0
    
        def __init__(self, x, y, z): #会在调用类时自动触发
            self.name = x #stu1.name='耗哥'
            self.age = y  #stu1.age=18
            self.sex = z #stu1.sex='male'
            OldboyStudent.count+=1
    
        def choose_course(self):
            print('is choosing course')
    
    
    # 先从对象自己的名称空间找,没有则去类中找,如果类也没有则报错
    stu1=OldboyStudent('耗哥',18,'male')
    stu2=OldboyStudent('猪哥',17,'male')
    stu3=OldboyStudent('帅翔',19,'female')
    
    print(OldboyStudent.count)
    print(stu1.count)
    print(stu2.count)
    print(stu3.count)

    绑定方法

    class OldboyStudent:
        school='oldboy'
    
    
        def __init__(self, x, y, z): #会在调用类时自动触发
            self.name = x #stu1.name='耗哥'
            self.age = y  #stu1.age=18
            self.sex = z #stu1.sex='male'
    
        def choose_course(self,x):
            print('%s is choosing course' %self.name)
    
        def func():
            pass
    # 类名称空间中定义的数据属性和函数属性都是共享给所有对象用的
    # 对象名称空间中定义的只有数据属性,而且时对象所独有的数据属性
    
    stu1=OldboyStudent('耗哥',18,'male')
    stu2=OldboyStudent('猪哥',17,'male')
    stu3=OldboyStudent('帅翔',19,'female')
    
    # print(stu1.name)
    # print(stu1.school)
    
    
    # 类中定义的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数而已,意味着需要完全遵循函数的参数规则,该传几个值就传几个
    # print(OldboyStudent.choose_course)
    # OldboyStudent.choose_course(123)
    
    # 类中定义的函数是共享给所有对象的,对象也可以使用,而且是绑定给对象用的,
    #绑定的效果:绑定给谁,就应该由谁来调用,谁来调用就会将谁当作第一个参数自动传入
    # print(id(stu1.choose_course))
    # print(id(stu2.choose_course))
    # print(id(stu3.choose_course))
    # print(id(OldboyStudent.choose_course))
    
    # print(id(stu1.school))
    # print(id(stu2.school))
    # print(id(stu3.school))
    #
    # print(id(stu1.name),id(stu2.name),id(stu3.name))
    
    
    # stu1.choose_course(1)
    # stu2.choose_course(2)
    # stu3.choose_course(3)
    stu1.func()
    
    # 补充:类中定义的函数,类确实可以使用,但其实类定义的函数大多情况下都是绑定给对象用的,所以在类中定义的函数都应该自带一个参数self

    类与类型

    #在python3中统一了类与类型的概念,类就是类型
    class OldboyStudent:
        school='oldboy'
    
        def __init__(self, x, y, z): #会在调用类时自动触发
            self.name = x #stu1.name='耗哥'
            self.age = y  #stu1.age=18
            self.sex = z #stu1.sex='male'
    
        def choose_course(self,x):
            print('%s is choosing course' %self.name)
    
    stu1=OldboyStudent('耗哥',18,'male')
    # stu1.choose_course(1) #OldboyStudent.choose_course(stu1,1)
    # OldboyStudent.choose_course(stu1,1)
    
    
    l=[1,2,3] #l=list([1,2,3])
    # print(type(l))
    # l.append(4) #list.append(l,4)
    list.append(l,4)
    print(l)

    继承与派生

    '''
    1、什么是继承
        继承是一种新建类的方式,新建的类称为子类,被继承的类称为父类
        继承的特性是:子类会遗传父类的属性
        强调:继承是类与类之间的关系
    
    2、为什么用继承
        继承的好处就是可以减少代码的冗余
    
    3、如何用继承
        在python中支持一个类同时继承多个父类
        在python3中
            如果一个类没有继承任何类,那默认继承object类
        在python2中:
            如果一个类没有继承任何类,不会继承object类
    
        新式类
            但凡继承了object的类以及该类的子类,都是新式类
        经典类
            没有继承object的类以及该类的子类,都是经典类
    
        在python3中都是新式类,只有在python2中才区别新式类与经典类
    
        新式类vs经典类?
    
    '''
    class Parent1(object):
        pass
    
    class Parent2(object):
        pass
    
    class Sub1(Parent1,Parent2):
        pass
    
    # print(Sub1.__bases__)
    print(Parent1.__bases__)
    print(Parent2.__bases__)

    继承的应用

    #派生:子类中新定义的属性,子类在使用时始终以自己的为准
    class OldboyPeople:
        school = 'oldboy'
        def __init__(self,name,age,sex):
            self.name = name #tea1.name='egon'
            self.age = age #tea1.age=18
            self.sex = sex #tea1.sex='male'
    
    
    
    class OldboyStudent(OldboyPeople):
        def choose_course(self):
            print('%s is choosing course' %self.name)
    
    
    class OldboyTeacher(OldboyPeople):
        #            tea1,'egon',18,'male',10
        def __init__(self,name,age,sex,level):
            # self.name=name
            # self.age=age
            # self.sex=sex
            OldboyPeople.__init__(self,name,age,sex)
            self.level=level
    
        def score(self,stu_obj,num):
            print('%s is scoring' %self.name)
            stu_obj.score=num
    
    stu1=OldboyStudent('耗哥',18,'male')
    tea1=OldboyTeacher('egon',18,'male',10)
    
    #对象查找属性的顺序:对象自己-》对象的类-》父类-》父类。。。
    # print(stu1.school)
    # print(tea1.school)
    # print(stu1.__dict__)
    # print(tea1.__dict__)
    
    tea1.score(stu1,99)
    
    print(stu1.__dict__)
    
    
    # 在子类派生出的新功能中重用父类功能的方式有两种:
    #1、指名道姓访问某一个类的函数:该方式与继承无关
    
    
    # class Foo:
    #     def f1(self):
    #         print('Foo.f1')
    #
    #     def f2(self):
    #         print('Foo.f2')
    #         self.f1()
    #
    # class Bar(Foo):
    #     def f1(self):
    #         print('Bar.f1')
    #
    # #对象查找属性的顺序:对象自己-》对象的类-》父类-》父类。。。
    # obj=Bar()
    # obj.f2()
    # '''
    # Foo.f2
    # Bar.f1
    # '''

     组合

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

    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,stu_id):
            OldboyPeople.__init__(self,name,age,sex)
            self.stu_id=stu_id
    
        def choose_course(self):
            print('%s is 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
            print('老师[%s]为学生[%s]打分[%s]' %(self.name,stu.name,num))
    
    
    stu1=OldboyStudent('猪哥',19,'male',1)
    tea1=OldboyTeacher('egon',18,'male',10)
    
    stu1.choose_course()
    tea1.score(stu1,100)
    print(stu1.__dict__)
    
    '''
    class Course:
        def __init__(self,name,period,price):
            self.name=name
            self.period=period
            self.price=price
    
        def tell_info(self):
            msg="""
            课程名:%s
            课程周期:%s
            课程价钱:%s
            """ %(self.name,self.period,self.price)
            print(msg)
    
    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,stu_id):
            OldboyPeople.__init__(self,name,age,sex)
            self.stu_id=stu_id
    
        def choose_course(self):
            print('%s is 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
            print('老师[%s]为学生[%s]打分[%s]' %(self.name,stu.name,num))
    
    # 创造课程
    python=Course('python全栈开发','5mons',3000)
    linux=Course('linux运维','5mons',800)
    # python.tell_info()
    # linux.tell_info()
    
    
    # 创造学生与老师
    stu1=OldboyStudent('猪哥',19,'male',1)
    tea1=OldboyTeacher('egon',18,'male',10)
    
    
    # 将学生、老师与课程对象关联/组合
    stu1.course=python
    tea1.course=linux
    
    stu1.course.tell_info()
    tea1.course.tell_info()

    菱形继承问题

    1、菱形继承
    当一个子继承多个父类时,多个父类最终继承了同一个类,称之为菱形继承

    2、菱形继承的问题:
    python2区分经典类与新式类,如果子的继承是一个菱形继承,那么经典类与形式的区别为?
    经典类下查找属性:深度优先查找
    新式类下查找属性:广度优先查找

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

    子类调用父类的方法

    # 在子派生的新方法中重用父类功能的两种方式
    # 方式一:与继承无关
    #指名道姓法,直接用:类名.函数名
    # 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,stu_id):
    #         OldboyPeople.__init__(self,name,age,sex)
    #         self.stu_id=stu_id
    #
    #     def choose_course(self):
    #         print('%s is choosing course' %self.name)
    
    
    # 方式二:严格以来继承属性查找关系
    # super()会得到一个特殊的对象,该对象就是专门用来访问父类中的属性的(按照继承的关系)
    # super().__init__(不用为self传值)
    # 注意:
    # super的完整用法是super(自己的类名,self),在python2中需要写完整,而python3中可以简写为super()
    # 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,stu_id):
    #         # OldboyPeople.__init__(self,name,age,sex)
    #         super(OldboyStudent,self).__init__(name,age,sex)
    #         self.stu_id=stu_id
    #
    #     def choose_course(self):
    #         print('%s is choosing course' %self.name)
    #
    #
    # stu1=OldboyStudent('猪哥',19,'male',1)
    # print(stu1.__dict__)
    #
    # print(OldboyStudent.mro())
    
    
    class A:
        def f1(self):
            print('A.f1')
    
    class B:
        def f2(self):
            super().f1()
            print('B.f2')
    
    class C(B,A):
        pass
    
    obj=C()
    print(C.mro()) #C-》B->A->object
    obj.f2()

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

    多态和多态性

    '''
    1 什么是多态
        多态指的是同一种事物的多种形态
            水-》冰、水蒸气、液态水
            动物-》人、狗、猪
    
    2 为和要用多态
        多态性:
        继承同一个类的多个子类中有相同的方法名
        那么子类产生的对象就可以不用考虑具体的类型而直接调用功能
    
    3 如何用
    '''
    import abc
    
    class Animal(metaclass=abc.ABCMeta):
        @abc.abstractmethod
        def speak(self):
            pass
        @abc.abstractmethod
        def eat(self):
            pass
    
    # Animal() #强调:父类是用来指定标准的,不能被实例化
    
    class People(Animal):
        def speak(self):
            print('say hello')
    
        def eat(self):
            pass
    
    class Dog(Animal):
        def speak(self):
            print('汪汪汪')
    
        def eat(self):
            pass
    class Pig(Animal):
        def speak(self):
            print('哼哼哼')
    
        def eat(self):
            pass
    
    
    
    peo1=People()
    dog1=Dog()
    pig1=Pig()
    #
    #
    # peo1.speak()
    # dog1.speak()
    # pig1.speak()
    
    # def my_speak(animal):
    #     animal.speak()
    #
    # my_speak(peo1)
    # my_speak(dog1)
    # my_speak(pig1)
    
    #
    # l=[1,2,3]
    # s='helllo'
    # t=(1,2,3)
    #
    # print(l.__len__())
    # print(s.__len__())
    # print(t.__len__())
    #
    # # def len(obj):
    # #     return obj.__len__()
    #
    # print(len(l)) # l.__len__()
    # print(len(s)) #s.__len__()
    # print(len(t))
    
    # python推崇的是鸭子类型,只要你叫的声音像鸭子,并且你走路的样子也像鸭子,那你就是鸭子
    
    class Disk:
        def read(self):
            print('disk read')
    
        def write(self):
            print('disk wirte')
    
    
    class Process:
        def read(self):
            print('process read')
    
        def write(self):
            print('process wirte')
    
    
    class File:
        def read(self):
            print('file read')
    
        def write(self):
            print('file wirte')
    
    
    
    obj1=Disk()
    obj2=Process()
    obj3=File()
    
    
    
    obj1.read()
    obj1.write()

     封装

    '''
    1、什么封装
        封:属性对外是隐藏的,但对内是开放的
        装:申请一个名称空间,往里装入一系列名字/属性
    
    2、为什么要封装
        封装数据属性的目的
            首先定义属性的目的就是为了给类外部的使用使用的,
            隐藏之后是为了不让外部使用直接使用,需要类内部开辟一个接口
            然后让类外部的使用通过接口来间接地操作隐藏的属性。
            精髓在于:我们可以在接口之上附加任意逻辑,从而严格控制使用者对属性的操作
    
        封装函数属性
            首先定义属性的目的就是为了给类外部的使用使用的,
            隐藏函数属性是为了不让外不直接使用,需要类内部开辟一个接口
            然后在接口内去调用隐藏的功能
            精髓在于:隔离了复杂度
    
    
    
    3、如何封装
    
    '''
    # 如何隐藏:在属性前加上__开头
    
    
    #1、 这种隐藏仅仅只是一种语法上的变形操作
    #2、 这种语法上的变形只在类定义阶段发生一次,因为类体代码仅仅只在类定义阶段检测一次
    #3、 这种隐藏是对外不对内的,即在类的内部可以直接访问,而在类的外则无法直接访问,原因是
    #    在类定义阶段,类体内代码统一发生了一次变形
    
    #4、 如果不想让子类的方法覆盖父类的,可以将该方法名前加一个__开头
    
    
    # class People:
    #     __country='China' #_People__country='China'
    #     __n=100 #_People__n=100
    #     def __init__(self,name,age,sex):
    #         self.__name=name #self._People__name=name
    #         self.age=age
    #         self.sex=sex
    #
    #     def eat(self):
    #         print('eat.....')
    #         print(People.__country) #People._People__country
    #         print(self.__name) #self._People__name
    
    # People.eat(123)
    # print(People.__country)
    
    # peo1=People('egon',18,'male')
    # peo1.eat()
    # print(peo1.__name)
    
    # print(People.__dict__)
    # print(People.__country)
    # print(People._People__country)
    
    # People.__x=11
    # print(People.__dict__)
    
    
    # peo1=People('egon',18,'male')
    # print(peo1.__dict__)
    # peo1.__x=111
    # print(peo1.__dict__)
    
    # class Foo:
    #     def __f1(self): #_Foo__f1
    #         print('Foo.f1')
    #
    #     def f2(self):
    #         print('Foo.f2')
    #         self.__f1() #self._Foo__f1
    #
    # class Bar(Foo):
    #     def __f1(self): #_Bar__f1
    #         print('Bar.f1')
    #
    # obj=Bar()
    # obj.f2()
    
    
    
    
    class People:
        def __init__(self,name,age):
            self.__name=name
            self.__age=age
    
        def tell_info(self):
            print('%s:%s' %(self.__name,self.__age))
    
        def set_info(self,name,age):
            if type(name) is not str:
                # print('用户名必须为str类型')
                # return
                raise TypeError('用户名必须为str类型')
    
            if type(age) is not int:
                # print('年龄必须为int类型')
                # return
                raise TypeError('年龄必须为int类型')
            self.__name=name
            self.__age=age
    
    peo1=People('egon',18)
    # peo1.name=123
    # peo1.age
    # peo1.tell_info()
    
    peo1.set_info('egon',19)
    # peo1.tell_info()

    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)
    #
    # peo1=People('egon',75,1.8)
    #
    # peo1.height=1.85
    # print(peo1.bmi)
    
    
    '''
    class People:
        def __init__(self,name):
            self.__name=name
    
        @property # 查看obj.name
        def name(self):
            return '<名字是:%s>' %self.__name
    
        @name.setter #修改obj.name=值
        def name(self,name):
            if type(name) is not str:
                raise TypeError('名字必须是str类型傻叉')
            self.__name=name
    
        @name.deleter #删除del obj.name
        def name(self):
            # raise PermissionError('不让删')
            print('不让删除傻叉')
            # del self.__name
    
    peo1=People('egon')
    # print(peo1.name)
    
    # print(peo1.name)
    
    # peo1.name='EGON'
    # print(peo1.name)
    
    del peo1.name
    
    '''
    
    
    class People:
        def __init__(self,name):
            self.__name=name
    
    
        def tell_name(self):
            return '<名字是:%s>' %self.__name
    
        def set_name(self,name):
            if type(name) is not str:
                raise TypeError('名字必须是str类型傻叉')
            self.__name=name
    
        def del_name(self):
            print('不让删除傻叉')
    
        name=property(tell_name,set_name,del_name)
    
    
    peo1=People('egon')
    
    print(peo1.name)
    peo1.name='EGON'
    print(peo1.name)
    del peo1.name

     绑定方法与非绑定方法

    '''
    1、绑定方法
        特性:绑定给谁就应该由谁来调用,谁来调用就会将谁当作第一个参数自动传入
             《《《精髓在于自动传值》》》
    
        绑定方法分为两类:
            1.1 绑定给对象方法
                在类内部定义的函数(没有被任何装饰器修饰的),默认就是绑定给对象用的
            1.2 绑定给类的方法:
                在类内部定义的函数如果被装饰器@classmethod装饰,
                那么则是绑定给类的,应该由类来调用,类来调用就自动将类当作第一个参数自动传入
    
    
    
    2、非绑定方法
        类中定义的函数如果被装饰器@staticmethod装饰,那么该函数就变成非绑定方法
        既不与类绑定,又不与对象绑定,意味着类与对象都可以来调用
        但是无论谁来调用,都没有任何自动传值的效果,就是一个普通函数
    
    
    
    
    
    3 应用
        如果函数体代码需要用外部传入的类,则应该将该函数定义成绑定给类的方法
        如果函数体代码需要用外部传入的对象,则应该将该函数定义成绑定给对象的方法
        如果函数体代码既不需要外部传入的类也不需要外部传入的对象,则应该将该函数定义成非绑定方法/普通函数
    
    
    '''
    
    # class Foo:
    #     @classmethod
    #     def f1(cls):
    #         print(cls)
    #
    #     def f2(self):
    #         print(self)
    #
    #
    # obj=Foo()
    # print(obj.f2)
    # print(Foo.f1)
    
    # Foo.f1()
    # print(Foo)
    
    
    #1、f1绑定给类的
    # 了解:绑定给类的应该由类来调用,但对象其实也可以使用,只不过自动传入的仍然是类
    # print(Foo.f1)
    # print(obj.f1)
    # Foo.f1()
    # obj.f1()
    
    #2、f2是绑定给对象的
    # obj.f2()
    # Foo.f2(obj)
    
    import settings
    import uuid
    
    class Mysql:
        def __init__(self,ip,port):
            self.uid=self.create_uid()
            self.ip=ip
            self.port=port
    
        def tell_info(self):
            print('%s:%s' %(self.ip,self.port))
    
        @classmethod
        def from_conf(cls):
            return cls(settings.IP, settings.PORT)
    
        @staticmethod
        def func(x,y):
            print('不与任何人绑定')
    
        @staticmethod
        def create_uid():
            return uuid.uuid1()
    
    # 默认的实例化方式:类名(..)
    obj=Mysql('10.10.0.9',3307)
    
    # 一种新的实例化方式:从配置文件中读取配置完成实例化
    # obj1=Mysql.from_conf()
    # obj1.tell_info()
    
    # obj.func(1,2)
    # Mysql.func(3,4)
    # print(obj.func)
    # print(Mysql.func)
    
    print(obj.uid)

     补充内置函数

    class Foo:
        pass
    
    obj=Foo()
    
    print(isinstance(obj,Foo))
    
    # 在python3中统一类与类型的概念
    # d={'x':1} #d=dict({'x':1} #)
    
    # print(type(d) is dict)
    # print(isinstance(d,dict))
    
    # issubclass()
    
    
    class Parent:
        pass
    
    class Sub(Parent):
        pass
    
    print(issubclass(Sub,Parent))
    print(issubclass(Parent,object))

     反射

    '''
    1、什么是反射
        通过字符串来操作类或者对象的属性
    
    2、如何用
        hasattr
        getattr
        setattr
        delattr
    
    
    '''
    
    class People:
        country='China'
        def __init__(self,name):
            self.name=name
    
        def eat(self):
            print('%s is eating' %self.name)
    
    peo1=People('egon')
    
    
    # print(hasattr(peo1,'eat')) #peo1.eat
    
    # print(getattr(peo1,'eat')) #peo1.eat
    # print(getattr(peo1,'xxxxx',None))
    
    # setattr(peo1,'age',18) #peo1.age=18
    # print(peo1.age)
    
    # print(peo1.__dict__)
    # delattr(peo1,'name') #del peo1.name
    # print(peo1.__dict__)
    
    
    class Ftp:
        def __init__(self,ip,port):
            self.ip=ip
            self.port=port
    
        def get(self):
            print('GET function')
    
        def put(self):
            print('PUT function')
    
        def run(self):
            while True:
                choice=input('>>>: ').strip()
                # print(choice,type(choice))
                # if hasattr(self,choice):
                #     method=getattr(self,choice)
                #     method()
                # else:
                #     print('输入的命令不存在')
    
                method=getattr(self,choice,None)
                if method is None:
                    print('输入的命令不存在')
                else:
                    method()
    
    conn=Ftp('1.1.1.1',23)
    conn.run()

    __setattr__,__delattr__,__getattr__

    class Foo:
        x=1
        def __init__(self,y):
            self.y=y
    
        def __getattr__(self, item):
            print('----> from getattr:你找的属性不存在')
    
    
        def __setattr__(self, key, value):
            print('----> from setattr')
            # self.key=value #这就无限递归了,你好好想想
            # self.__dict__[key]=value #应该使用它
    
        def __delattr__(self, item):
            print('----> from delattr')
            # del self.item #无限递归了
            self.__dict__.pop(item)
    
    #__setattr__添加/修改属性会触发它的执行
    f1=Foo(10)
    print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
    f1.z=3
    print(f1.__dict__)
    
    #__delattr__删除属性的时候会触发
    f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
    del f1.a
    print(f1.__dict__)
    
    #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
    f1.xxxxxx
    

    __str__,__repr__,__format__

    改变对象的字符串显示__str__,__repr__

    自定制格式化字符串__format__

    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    format_dict={
        'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
        'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
        'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
    }
    class School:
        def __init__(self,name,addr,type):
            self.name=name
            self.addr=addr
            self.type=type
    
        def __repr__(self):
            return 'School(%s,%s)' %(self.name,self.addr)
        def __str__(self):
            return '(%s,%s)' %(self.name,self.addr)
    
        def __format__(self, format_spec):
            # if format_spec
            if not format_spec or format_spec not in format_dict:
                format_spec='nat'
            fmt=format_dict[format_spec]
            return fmt.format(obj=self)
    
    s1=School('oldboy1','北京','私立')
    print('from repr: ',repr(s1))  #from repr: School(oldboy1,北京)
    print('from str: ',str(s1))    #from str: (oldboy1,北京)
    print(s1)  #(oldboy1,北京)
    '''
    str函数或者print函数--->obj.__str__()
    repr或者交互式解释器--->obj.__repr__()
    如果__str__没有被定义,那么就会使用__repr__来代替输出
    注意:这俩方法的返回值必须是字符串,否则抛出异常
    '''
    print(format(s1,'nat'))
    print(format(s1,'tna'))
    print(format(s1,'tan'))
    print(format(s1,'asfdasdffd'))
    自定义format练习
    date_dic={
        'ymd':'{0.year}:{0.month}:{0.day}',
        'dmy':'{0.day}/{0.month}/{0.year}',
        'mdy':'{0.month}-{0.day}-{0.year}',
    }
    class Date:
        def __init__(self,year,month,day):
            self.year=year
            self.month=month
            self.day=day
    
        def __format__(self, format_spec):
            if not format_spec or format_spec not in date_dic:
                format_spec='ymd'
            fmt=date_dic[format_spec]
            return fmt.format(self)
    
    d1=Date(2016,12,29)
    print(format(d1))
    print('{:mdy}'.format(d1))
    
    

     自定义内置方法定制类

    #1、__str__方法
    # class People:
    #     def __init__(self,name,age):
    #         self.name=name
    #         self.age=age
    #
    #     #在对象被打印时,自动触发,应该在该方法内采集与对象self有关的信息,然后拼成字符串返回
    #     def __str__(self):
    #         # print('======>')
    #         return '<name:%s age:%s>' %(self.name,self.age)
    # obj=People('egon',18)
    # obj1=People('alex',18)
    # print(obj)  #obj.__str__()
    # print(obj)  #obj.__str__()
    # print(obj)  #obj.__str__()
    # print(obj1)  #obj1.__str__()
    
    
    # d={'x':1} #d=dict({'x':1})
    # print(d)
    
    
    #1、__del__析构方法
    # __del__会在对象被删除之前自动触发
    class People:
        def __init__(self,name,age):
            self.name=name
            self.age=age
            self.f=open('a.txt','rt',encoding='utf-8')
    
        def __del__(self):
            # print('run=-====>')
            # 做回收系统资源相关的事情
            self.f.close()
    
    obj=People('egon',18)
    
    print('')

    元类

    '''
    1、什么是元类
        在python中一切皆对象,那么我们用class关键字定义的类本身也是一个对象
        负责产生该对象的类称之为元类,即元类可以简称为类的类
    
        class Foo: # Foo=元类()
            pass
    2、为何要用元类
        元类是负责产生类的,所以我们学习元类或者自定义元类的目的
        是为了控制类的产生过程,还可以控制对象的产生过程
    
    3、如何用元类
    
    '''
    #1、储备知识:内置函数exec的用法
    # cmd="""
    # x=1
    # def func(self):
    #     pass
    # """
    # class_dic={}
    # exec(cmd,{},class_dic)
    #
    # print(class_dic)
    
    #2、创建类的方法有两种
    # 大前提:如果说类也是对象的化,那么用class关键字的去创建类的过程也是一个实例化的过程
    # 该实例化的目的是为了得到一个类,调用的是元类
    #2.1 方式一:用的默认的元类type
    # class People: #People=type(...)
    #     country='China'
    #     def __init__(self,name,age):
    #         self.name=name
    #         self.age=age
    #
    #     def eat(self):
    #         print('%s is eating' %self.name)
    
    # print(type(People))
    
    #2.1.1 创建类的3个要素:类名,基类,类的名称空间
    class_name='People'
    class_bases=(object,)
    class_dic={}
    class_body="""
    country='China'
    def __init__(self,name,age):
        self.name=name
        self.age=age
    
    def eat(self):
        print('%s is eating' %self.name)
    """
    exec(class_body,{},class_dic)
    
    # 准备好创建类的三要素
    # print(class_name)
    # print(class_bases)
    # print(class_dic)
    
    # People=type(类名,基类,类的名称空间)
    # People1=type(class_name,class_bases,class_dic)
    # print(People1)
    # obj1=People1('egon',18)
    # print(People)
    # obj=People('egon',18)
    #
    # obj1.eat()
    # obj.eat()
    
    '''
    #2.2 方式二:用的自定义的元类
    class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
        def __init__(self,class_name,class_bases,class_dic):
            print(self) #现在是People
            print(class_name)
            print(class_bases)
            print(class_dic)
            super(Mymeta,self).__init__(class_name,class_bases,class_dic) #重用父类的功能
    
    # 分析用class自定义类的运行原理(而非元类的的运行原理):
    #1、拿到一个字符串格式的类名class_name='People'
    #2、拿到一个类的基类们class_bases=(obejct,)
    #3、执行类体代码,拿到一个类的名称空间class_dic={...}
    #4、调用People=type(class_name,class_bases,class_dic)
    class People(object,metaclass=Mymeta): #People=Mymeta(类名,基类们,类的名称空间)
        country='China'
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def eat(self):
            print('%s is eating' %self.name)
    
    
    # 应用:自定义元类控制类的产生过程,类的产生过程其实就是元类的调用过程
    
    class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
        def __init__(self,class_name,class_bases,class_dic):
            if class_dic.get('__doc__') is None or len(class_dic.get('__doc__').strip()) == 0:
                raise TypeError('类中必须有文档注释,并且文档注释不能为空')
            if not class_name.istitle():
                raise TypeError('类名首字母必须大写')
            super(Mymeta,self).__init__(class_name,class_bases,class_dic) #重用父类的功能
    
    class People(object,metaclass=Mymeta): #People=Mymeta('People',(object,),{....})
        """这是People类"""
        country='China'
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def eat(self):
            print('%s is eating' %self.name)
    '''
    
    
    #3 储备知识:__call__
    # class Foo:
    #     def __call__(self, *args, **kwargs):
    #         print(self)
    #         print(args)
    #         print(kwargs)
    #
    #
    # obj=Foo()
    #
    # # 要想让obj这个对象变成一个可调用的对象,需要在该对象的类中定义一个方法__call__方法
    # # 该方法会在调用对象时自动触发
    # obj(1,2,3,x=1,y=2)
    
    
    # 4、自定义元类来控制类的调用的过程,即类的实例化过程
    class Mymeta(type):
    
        def __call__(self, *args, **kwargs):
            # print(self) # self是People
            # print(args)
            # print(kwargs)
            # return 123
    
            # 1、先造出一个People的空对象
            obj=self.__new__(self)
            # 2、为该对空对象初始化独有的属性
            # print(args,kwargs)
            self.__init__(obj,*args,**kwargs)
    
            # 3、返回一个初始好的对象
            return obj
    
    
    class People(object,metaclass=Mymeta):
        country='China'
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def eat(self):
            print('%s is eating' %self.name)
    
        def __new__(cls, *args, **kwargs):
            print(cls)
            # cls.__new__(cls) # 错误
            obj=super(People,cls).__new__(cls)
            return obj
    
    # 分析:调用Pepole的目的
    #1、先造出一个People的空对象
    #2、为该对空对象初始化独有的属性
    # obj1=People('egon1',age=18)
    # obj2=People('egon2',age=18)
    # print(obj1)
    # print(obj2)
    
    obj=People('egon',age=18)
    print(obj.__dict__)
    print(obj.name)
    obj.eat()

      

  • 相关阅读:
    OGRE源代码resource分析
    全排列
    各种让人无语的库
    python Kmeans算法
    Linux服务器安装MariaDB数据库
    初探SEO,BSP收录速度测试
    MetaWeblog API调用
    Patterns
    腾讯。。。对Linux的支持程度直接扼杀了Linux在国内用户群的增长
    个人电子商务网站建设之——整站静态化实现的选择、设计与实现(二):静态页面的实现方式;
  • 原文地址:https://www.cnblogs.com/hanbowen/p/9224724.html
Copyright © 2011-2022 走看看