面向对象1


面向过程的概念

        面向过程核心是过程二字,解决问题的流程, 即先干什么,在干什么,最后干什么

        # 举例:
            1. 洗衣服
            2. 把大象放冰箱中需要几步?
                '''
                    1. 把冰箱门打开
                    2. 把大象放进去
                    3. 关上冰箱门
                '''
             3. 流水线生产饮料

            优点:复杂的问题流程化,进而简单化
            缺点:牵一发而动全身,扩展性差,可维护性差
            应用场景:对扩展性要求不高的地方, eg:安装包的使用

            # 注册的功能
                '''
                    1. 用户输入用户名和密码
                    2. 验证参数
                    3. 写入文件,注册成功
                '''

面向对象

        面向对象核心是对象二字
            什么是对象?
                1. 程序中:
                    函数:盛放数据的容器
                    对象:盛放数据和函数的容器
                2. 现实生活中:
                    一切皆对象
                    对象:特征与节能的结合体
               eg:

            优点:扩展性强,可维护性强
            缺点:编程复杂度高
            应用场景:对扩展性要求较高的地方。 eg:微信,qq

            # 举例:
                以学生选课系统为例

        # 版本3:

        def choose_course(stu_dict, course):
            stu_dict['course'].append(course)
            print('%s选课成功 %s' % (stu_dict['name'], stu_dict['course']))


        stu1 = {
            'name': 'jason',
            'age': 18,
            'gender': 'male',
            'course': [],
            'choose_course': choose_course
        }

        stu2 = {
            'name': 'ly',
            'age': 18,
            'gender': 'male',
            'course': [],
            'choose_course': choose_course
        }

        stu1['choose_course'](stu1, 'python')
        stu2['choose_course'](stu2, 'python')

类的定义和对象的产生

        对象: 特征与技能的结合体
        类:一系列对象相似的特征与相似的技能的结合体

        强调:站在不同的分类,划分的分类不一定一样

        # 问题来了:
            到底是先有类还是先有对象?
            1. 程序中:
                必须先定义类,然后调用类产生对象
            2. 现实生活中:
                先有对象,在有人类

        '''
        使用专业的语法定义类:
            1. 定义函数
                def 函数名():
                    pass

            2. 定义类:
                class 类名():
                    pass

        '''

        # 定义类:
        '''
            发生了什么事?
                1. 立即执行类体代码
                2. 产生一个类的名称空间,把类体里面执行的名字都扔到名称空间中(大字典)
                3. 把类的名称空间绑定给__dict__, 类名.__dict__
        '''
        # 类名一般情况首字母大写
        class Student():
            # 定义一个属性
            school = 'SH'

            # 定义一个技能(函数)
            def choose_course(stu_dict, course):
                stu_dict['course'].append(course)
                print('%s选课成功 %s' % (stu_dict['name'], stu_dict['course']))

            print('>>>>>>')

        # 查看类的名称空间
        print(Student.__dict__)


        # 产生对象
        # 调用类产生对象,默认产生的就是一个空对象{}

        stu1 = Student()
        stu2 = Student()
        stu3 = Student()

        print(stu1.__dict__)
        print(stu2.__dict__)
        print(stu3.__dict__)

给对象定制自己独有的属性

        # 版本3:
        class Student():
            # 定义一个属性
            school = 'SH'

            # 初始化方法
            # 调用类自动触发的函数
            # 该方法不是一定要定义,需要用到就定义,不需要刻意不定义
            def __init__(stu_obj, name, age, gender):
                # 空对象.name = name
                # 空对象.age = age
                # 空对象.gender = gender
                stu_obj.name = name  # stu1.__dict__['name'] = 'jason'
                stu_obj.age = age  # stu1.__dict__['age'] = 18
                stu_obj.gender = gender  # stu1.__dict__['gender'] = 'male'、
                # return None # 在这个方法中不能有返回值,
            # 定义一个技能(函数)
            def choose_course(stu_dict, course):
                stu_dict['course'].append(course)
                print('%s选课成功 %s' % (stu_dict['name'], stu_dict['course']))


        # 调用类发生了几件事?
        '''
            1. 得到一个空对象
            2. 调用了Student.__dict__(空对象,'ly', 18, 'male'),
            3. 得到一个初始化的结果。
        '''
        stu1 = Student('ly', 18, 'male')
        stu2 = Student('jason', 18, 'male')
        # stu1 = Student()
        # print(stu1.__dict__)
        # print(stu2.__dict__)

        # print(stu1.name)
        # print(stu2.name)

        # 属性的查找:先从自己的对象中查找,然后在去产生对象的类中取找

        stu1.school = 'aaaa'
        print(stu1.school)

属性的查找顺序

         # 版本3:
        class Student():
            # 定义一个属性
            school = 'SH'

            def __init__(self, name, age, gender, course=None):
                if course is None:
                    course = []
                self.name = name  # stu1.__dict__['name'] = 'jason'
                self.age = age  # stu1.__dict__['age'] = 18
                self.gender = gender  # stu1.__dict__['gender'] = 'male'
                self.course = course
            def choose_course(self, course):
                # stu_dict => stu
                self.course.append(course)
                print('%s选课成功 %s' % (self.name, self.course))

            def func(self, name, age):
                pass

        # 属性的查找:
        # 1. 类属性: 在类中写的属性就称为类属性
        # 2. 对象属性:在对象自己的名称空间中的属性就是对象属性

        # 类属性的查找
        # 1. 查
        # print(Student.school)

        # 2. 增加
        # Student.country = 'China'


        # 3. 改
        # Student.school = 'BJ'

        # 4. 删除
        # del Student.school
        # print(Student.__dict__)
        # {}
        stu = Student('ly', 18, 'male')  # 实例化对象, stu就是一个实例
        # 对象属性
        # 1. 查
        # print(stu.name)
        # print(stu.age)
        # print(stu.gender)

        # 2. 增
        # stu.aaa = 'aaa'
        #
        # # 3. 改
        # stu.name = 'bbb'

        # 4. 删除
        # del stu.name
        # print(stu.__dict__)


        # 类中的方法,类可以调用,对象也可以调用
        # 类调用方法
        # Student.choose_course(stu, 'python') # 类来调用,函数的参数有几个就要传几个
        # print(Student.choose_course)

        # 对象调用方法
        # 类中的方法,类可以调用,对象也可以调用, 但是,推荐对象来调用,因为对象来调用,会把自己当成第一个参数传递给函数
        stu.choose_course('python') # stu.choose_course(stu, 'python')

        class Teacher():
            pass
        print(isinstance(123, int))
        print(isinstance(stu, Teacher))

小练习案例

        题目:
            1. 定义一个类,产生一堆对象

            2. 统计产生了多少个对象
                '''思路:定义一个计数器,每产生一个对象,计数器加1'''

           class Student():
            school = 'SH'
            count = 0  # 专门用来计数

            def __init__(self, name, age):
                # self => stu => {'name':'ly', 'age': 18, 'count':1}
                # self => stu1 => {'name':'ly1', 'age': 18, 'count':1}
                # self => stu2 => {'name':'ly2', 'age': 18, 'count':1}
                self.name = name
                self.age = age
                # self.count = self.count + 1
                # Student.count += 1
                # self.__class__  # Student
                self.__class__.count += 1

绑定方法

        绑定方法分为2种:
            1. 绑定给对象的
                class Student():
            def __init__(self, name, age, gender):
                self.name = name
                self.age = age
                self.gender = gender

            # 绑定给对象的方法,对象来调用,会把自己当成第一个参数传到函数里面self
            def tell_info(self):
                print('name: %s,age:%s, gender:%s' % (self.name, self.age, self.gender))


                stu = Student('ly', 18, 'male')
                # print(stu.name)
                stu.tell_info() # stu.tell_info(stu)

            2. 绑定给类的

        class Mysql():
            def __init__(self, ip, port):
                self.ip = ip
                self.port = port

            @classmethod  # 该方法绑定给类了,以后有类来调用,会自动把类名当成第一个参数传过来,cls
            def from_conf(cls):
                # cls => Oracle
                # obj = Oracle(settings.IP, settings.PORT)
                obj = cls(settings.IP, settings.PORT)
                return obj
         Mysql.from_conf()

非绑定方法

        # 既不绑定给类,也不绑定给对象
        class Student():
            school = 'SH'
            def __init__(self, name, age):
                self.name = name
                self.age = age

            @staticmethod  # 静态方法
            def create_id():
                import uuid
                return uuid.uuid4()

        stu = Student('ly', 18)

        # print(stu.create_id())
        # print(Student.create_id())
        print(stu.create_id())

如何隐藏属性

        # 1. 如何隐藏
                # 1. 如何隐藏
        '''
            1. 在类定义阶段,发生了语法上的变形_类名__属性名
            2. 隐藏对外不对内
            3. 只有在类定义阶段发生变形,其他情况都不发生变形了

        为什么要隐藏: 类里面的隐藏属性, 类外部可以使用,但是目的不是让类外部使用的,类外部要是想用,在类内部开放接口进行访问
                    可以达到对外部数据的严格控制
        '''
        class Student():
            __school = 'SH' # _Student__school  => _类名__属性名
            def __init__(self, name, age):
                self.__name = name
                self.age = age

            def __tell_info(self):  # _Student__tell_info  => _类名__函数名
                print('name: %s, age: %s' % (self.__name, self.age))

            def get_school(self):
                return self.__school  # self._Student__school

            def set_school(self, v):
                if type(v) is not str:
                    print('数据类型不合法')
                # if isinstance(v, str):
                    return
                self.__school = v

property装饰器

        class Student():
            __school = 'SH'  # _Student__school  => _类名__属性名

            def __init__(self, name, age):
                self.__name = name
                self.age = age

            def __tell_info(self):  # _Student__tell_info  => _类名__函数名
                print('name: %s, age: %s' % (self.__name, self.age))

            @property  # 把方法伪装成属性
            def name(self):
                return "name:%s" % self.__name

            @name.setter
            def name(self, v):
                if type(v) is not str:
                    print('数据类型不合法')
                # if isinstance(v, str):
                    return
                self.__name = v

            @name.deleter
            def name(self):
                print('不让删')

        stu = Student('ly', 18)
        print(stu.get_name())

        stu.name = 123
        print(stu.name)

        del stu.name


        # 练习
        class Bmi():
            def __init__(self, height, weight):
                self.height = height
                self.weight = weight

            @property
            def get_bmi(self):
                return self.weight / (self.height ** 2)

        bmi = Bmi(1.8, 70)
        print(bmi.get_bmi)


        # 了解

        class Student():
            __school = 'SH'  # _Student__school  => _类名__属性名

            def __init__(self, name, age):
                self.__name = name
                self.age = age

            def __tell_info(self):  # _Student__tell_info  => _类名__函数名
                print('name: %s, age: %s' % (self.__name, self.age))

            def get_name(self):
                return "name:%s" % self.__name

            def set_name(self, v):
                if type(v) is not str:
                    print('数据类型不合法')
                    # if isinstance(v, str):
                    return
                self.__name = v

            def del_name(self):
                print('不让删')

            # 了解
            name = property(get_name, set_name, del_name)


        stu = Student('ly', 18)
        # print(stu.xxx)

        stu.name = 'aaa'
        print(stu.name)

py