zoukankan      html  css  js  c++  java
  • 面对对象基础

    在计算机创建一个人类对象

    要得到对象,必须先告诉计算机,这个对象具备什么特征和行为,所以需要先定义类

    类名要按照大驼峰的方式来书写 ThisIsPerson 每个单词首字母大写

    class People

    在类中描述对象的特征和行为

    class Person

      name='李四'

      sex=‘male’

      age=‘20’

    通过调用类,得到对象,也称之为实例化 或创建对象

    obj=Person()

    print(obj)

    这是一个Person类的对象,打印出来是它的地址

    使用对象的属性(说的就是特征)
    print(obj.name)
    print(obj.age)
    class Student:
        number = "007"
        name = "盖伦"
        sex = "man"
        age = 18
    
        # 学生的学校 由于每个学生的学校都是相同 所以将其放到类中
        school = "Tsinghua"
    
    
    
    # 创建了两个学生对象
    stu1 = Student()
    stu2 = Student()
    
    print(stu1)
    print(stu2)
    # 每个对象内存地址都是不同的 , 在创建对象时,计算机会申请一个新的内存空间,并将对象中的内容存进去
    
    print(id(stu1.name))
    print(id(stu2.name))
    
    # 由于name的值时声明在类中的,所以每个对象使用的都是同一份
    
    
    print(stu1.name)
    print(stu2.name)
    
    # 为对象单独制定属性
    stu1.name = "韩信"
    stu2.name = "陈大炮"
    
    
    print(stu1.name)
    print(stu2.name)
    
    
    # 每个对象的name属性都不同,则意味需要给每个对象单独指定name
    
    
    
    # 存储属性的位置有两个 一个是类中,还有一个对象中
    # 当每个对象的某个特征都相同时则放到类中
    # 当每个对象的某个特征都不同时则放到对象中
    
    # 通过__dict__可以获取一个对象中包含的内容
    stu1.age = 30
    print(stu1.__dict__)
    print(stu2.__dict__)
    
    
    # 获取类中包含的内容
    print(Student.__dict__)
    
    
    
    
    
    
    
    # 如何为对象增加属性
    # 存储属性的位置有两个 类 和对象
    "属性的访问顺序"
    class Car:
        c_type = "破鞋"
        color = "red"
        price = 400000
    
    
    c1 = Car()
    c2 = Car()
    
    print(c1.__dict__)
    print(c2.__dict__)
    print(c1.c_type)
    
    # 当对象中不存在是会到类中去找
    
    c1.c_type = "法拉利"
    print(c1.__dict__)
    print(c2.__dict__)
    print(c1.c_type)
    
    print(c2.c_type)
    # 如果对象中存在这个属性,优先访问对象中的属性
    print(Car.__dict__)
    
    # 查找顺序为 对象 ->  类
    
    # 当创建一个类的时候 会产生名称空间,存储类中名称和值的绑定关系
    # 当创建一个对象的时候 会产生名称空间,存储对象中名称和值的绑定关系
    # 类还有另一个作用 就是 作为对象的模板,所有属于同一个类的对象,都具备类中的公共内容
    
    # 即使我们什么都不写 类中也存在一些自带的属性,是从父类得到的(继承会详细讨论)
    class A:
        pass
    
    
    print(A.__dict__)
    属性的访问顺序
    # class Student:
    #     # 定义一个函数 用于为对象设置属性
    #     def set_attr(obj, name, sex, age):
    #         obj.name = name
    #         obj.sex = sex
    #         obj.age = age
    #     pass
    #
    #
    # stu1 = Student()
    # # 指定属性
    # stu1.name = "张无忌"
    # stu1.sex = "man"
    # stu1.age = 18
    #
    #
    # stu2 =Student()
    # stu2.name = "周芷若"
    # stu2.sex = "woman"
    # stu2.age = 78
    #
    #
    #
    #
    # # stu3 = Student()
    # # stu4 = Student()
    #
    #
    # # set_attr(stu3,"灭局","woman",88)
    # # set_attr(stu4,"金毛狮王","man",20)
    #
    #
    # # print(stu3.__dict__)
    # # print(stu4.__dict__)
    #
    #
    # # set_attr这个函数目的是用于设置对象的属性 ,如果没有对象则该函数没有存在的意义,也就是初始化函数与类应该是一个整体
    # # 应该讲这个函数放到类中
    # stu3 = Student()
    # stu4 = Student()
    #
    #
    # Student.set_attr(stu3,"金毛狮王","man",80)
    # print(stu3.__dict__)
    #
    #
    # Student.set_attr(stu4,"张全蛋","man",28)
    # print(stu4.__dict__)
    #
    #
    # # 现在已经简化了代码 但是对象的创建和初始化步骤是分开的, 通常对象一旦创建 就应该进行初始化,所以最好时将创建与初始化进绑定
    #
    # stu5 = Student()
    # print(stu5)
    #
    
    
    
    
    
    # 作为一个人 一旦出生 性别必须要指定
    # 带有__开头__结尾的函数 是一些特殊内置函数,会在某个时间点自动触发执行
    class Person:
        # 初始化函数名称是固定  该函数会在调用类是时自动执行,self参数必须有,表示要进行初始化的对象,系统会自动传值
        def __init__(self,name,age):
            print("执行了 __init__")
            print(self)
            self.name = name
            self.age =age
    
    p1 = Person("张三丰",80)
    
    print(p1.__dict__)
    
    p2 = Person("李狗蛋",20)
    print(p2.__dict__)
    
    # init 函数用于初始化对象,它会在创建对象时,自动执行,并传入调用类时传递的参数,第一个参数表示要初始化的对象本身,
    # self(第一个)参数不需要手动传递
    # self表示对象自己 是一个形式参数,名字可以随便取,但是不建议修改
    初始化函数
    """
        绑定方法
        什么是绑定 把两个东西捆绑在一起
        什么是方法 方法 就是 函数
            函数是专业术语,不好理解,面向对象编程思想,是要我们模仿现实生活中的抽象概念,为了方便理解就把函数称之为方法
    
        绑定方法就是 把对象与函数进行绑定
        为什么要把把对象与函数进行绑定ee4444444444 5rr     6   565
            调用函数 就变成了调用对象的方法
    
        对象本质上就是一种存放数据的容器
        函数是用于处理数据的代码
        绑定方法就是将数据与处理数据的函数绑定在一起
    
        最终问题是 为什么要把数据与处理数据的函数绑定在一起?
    
        如何使用绑定方法
    """
    class Student:
        school = "BeiJing"
    
        def __init__(self,name,sex,age):
            self.name = name
            self.sex = sex
            self.age = age
    
        def learning(self):
            print("正在学习..")
    
        def sayHI(self):
            print("hello my name is %s my age:%s my sex:%s" % (self.name,self.age,self.sex))
    
        # 默认情况下 在类中定义的函数都是绑定方法,共同点是,都会讲对象作为第一个参数self
    
    
    
    stu1 = Student("一个学生","man",18)
    
    stu1.sayHI()
    
    Student.sayHI(stu1)
    
    # 当用用对象来调用类中的方法时,默认把对象传入方法中
    # 而用类名来调用时,则需要手动传入对象
    
    
    print(stu1.sayHI)
    #<bound method Student.sayHI of <__main__.Student object at 0x000001784F889C50>>
    # 这是一个绑定方法,本质上是Student类中的sayHI函数 现在把这个函数绑定给了地址为0x000001784F889C50的对象
    
    
    
    stu2 = Student("李四","",19)
    stu2.sayHI()
    print(stu2.sayHI)
    
    # 只要拿到对象 就同事拿到了数据和处理数据的方法
    绑定方法
    为什么要绑定方法:
    # 第一个问题传递参数,必须手动传递,很有可能传参顺序而发生错误
    # 第二个问题每次处理数据 都需要手动传参数
    # 第三个问题 当要处理的数据特别的多 就不能再定义为变量了 你可以使用列表出来存储要处理的数据
    # 但是 每次处理 都需要先获取数据 在传递给处理数据的函数
    # 所以将 要处理的数据与 处理数据的函数进行绑定
    class Student:
        school = "beijing"
    
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        # 绑定方法分为两种 一种是绑定给对象的,一种绑定给类的
    
    
    
        # @classmethod
        # def print_school_name():
        #     print("学校名为:%s" % Student.school)
    
        # 绑定给类的方法 使用一个装饰器叫classmethod,必须有一个参数,表示当前类,参数名也可以自己定义,建议不要修改
        @classmethod
        def print_school(cls):  # 输出类里面叫school的属性
            print(cls.school)
    
        # def print_school2(self):  # 输出类里面叫school的属性
        #     print(self.school)
    
        # 这是绑定给对象的方法
        def sayHello(self):
            print(self.name, " 说: 你好")
    
    
    
    # # Student.print_school_name()
    #
    # Student.print_school()
    
    # 对象绑定方法  可以使用对象来调用 也可以使用类名来调用
    # 在对象调用时会自动传入对象自己
    # 类调用时不会自动传参
    
    # 类的绑定方法,对象和类都能调用,并且都会自动传入这个类
    # Student.print_school()
    # stu1 = Student("印度阿三","woman",20)
    # stu1.print_school()
    
    # 如何定义对象绑定方法 以及类的绑定方法
    # 在调用时的区别
    
    # 一个方法到底应该绑定给对象还是帮对给类?
    # 当要处理的数据包含在类中时,就应该绑定给类
    # 当要处理的数据包含在对象中时,就应该绑定给对象
    
    
    stu10 = Student("赵六","",20)
    # Student.print_school2(stu10)
    
    
    
    # 有一个Dog类  每一个Dog对象都应该会叫 会跑  请用面向对象来完成
    
    
    class Dog:
        def __init__(self,nikename,gender,age):
            self.nikename = nikename
            self.gender = gender
            self.age = age
    
        def run(self):
            print("不好了 ",self.nikename,"跑了 ")
    
        def bark(self):
            print("",self.nikename,"在瞎叫...")
    
    d1 = Dog("大金毛","母的",2)
    d2 = Dog("大黄","公的",3)
    
    d1.run()
    d2.bark()
    
    
    
    """
    # 类的绑定方法和对象的绑定方法的相同与不同
    相同点:
        1.都会自动传值
        2.都可以被类和对象调用
    
    不同点:
        1.对象绑定方法再对象调用时 传的是对象自己 而类绑定方法字自动传的是类自己
        2.第一个参数  个cls 一个叫self
    
    
    为什么要绑定?
    
    # 第一个问题传递参数,必须手动传递,很有可能传参顺序而发生错误
    # 第二个问题每次处理数据 都需要手动传参数
    # 第三个问题 当要处理的数据特别的多 就不能再定义为变量了 你可以使用列表出来存储要处理的数据
    但是 每次处理 都需要先获取数据 在传递给处理数据的函数
    之所以绑定 ,简化代码,提高效率 
    """
    绑定给类的方法
    class Teacher:
    
        def __init__(self,name,sex):
            self.name = name
            self.sex = sex
    
        # @staticmethod 用于定义个非绑定方法
        @staticmethod
        def test_func(num):
            print("test_func run!")
            print(num)
    
    Teacher.test_func(1)
    
    t1 = Teacher("矮根","")
    t1.test_func(100)
    print(t1.test_func)
    
    
    #  什么是非绑定方法 再类中 即不绑定给类 也不绑定给对象
    #  特点:没有自动传参数的效果 ,类和对象向都能调用,就是一个普通函数
    #  当你的这个功能不需要访问类的数据 也不需要访问对象的数据,就可以作为一个非绑定方法
    #  使用场景较少
    非绑定方法
    1.什么是继承
    继承是一种关系,必须存在两个对象才可能产生这种关系,在现实生活中的继承,王思聪可以继承王健林的财产
    被继承的称为父 继承的一方成为子

    在程序中继承指的是类与类之间的关系


    2.为什么要使用继承
    在生活中,通过继承 子可以直接享受父提供内容,例如财产
    在程序中,通过继承可以直接使用父类已有的代码

    class Parent:
        year = 2018
    
        def coding(self):
            print("正在编程........")
    
    
    
    class Sub(Parent):
        pass
    
    print(Parent.year)
    
    print(Sub.year)
    
    # Sub.coding()
    
    
    s = Sub()
    print(s.year) # 子类可以使用父类中的属性
    s.coding() # 子类也可以父类中的函数
    继承的使用
    class Person:
        def __init__(self ,name ,age ,sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def eat(self):
            print("正在吃饭....")
    
        def study(self):
            print("正在学习....")
    
    class Teacher(Person):
    
        def teaching(self):
            print("老师正在上课......")
    
    t1 = Teacher("blex" ,30 ,"woman")
    t1.eat()
    t1.study()
    
    
    class Student(Person):
        pass
    
    stu1 = Student("张三" ,20 ,"man")
    stu1.eat()
    stu1.study()
    
    # stu1.teaching()
    
    # 学生继承了老师 减少了重复代码,但是继承到一些学生不应该有的内容
    # 正确姿势:抽取公共的父类  抽象
    # 抽象是 抽取多个类中相同的部分形成另一个类
    
    
    
    # 通过继承 避免了重复代码的编写
    # 通过抽象 避免了继承到一些不应该有的内容
    # 应该先抽象再继承
    # 再抽取过程中 可能会一些跟业务需求无关的类,这是正常的 这些称之为公共父类
    # 公共父类的作用是存储多个子类相同属性和技能
    继承的好处
    
    
    派生指的是 子类继承某个父类 并且拥有自己独特的属性或技能   该子类称之为派生类
    只要子类中出现了任何新内容,它就是一个派生类
    class Person:
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def sayHI(self):
            print("hello 我是%s 今年%s岁 性别:%s" % (self.name,self.age,self.sex))
    
    
    # Test不能称为派生类 , 因为没与任何独特的内容与父类完全一致
    class Test(Person):
        pass
    
    # 派生类属于子类吗?   派生类一定是某个子类
    # Student类就成为 Person类的派生类
    
    
    class Student(Person):
        def __init__(self,name,age,sex,number):
            self.name = name
            self.age = age
            self.sex = sex
            self.number = number
    
        # 上课
        def up_class(self):
            print("%s 正在上课.....")
    class Person:
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
            print(self)
    
        def sayHI(self):
            print("hello 我是%s 今年%s岁 性别:%s" % (self.name,self.age,self.sex))
    
    
    class Student(Person):
        def __init__(self,name,age,sex,number):
            # self.name = name
            # self.age = age
            # self.sex = sex
            #上述代码与父类中完全相同
            Person.__init__(self,name,age,sex)
            self.number = number
        # 上课
        def up_class(self):
            print("%s 正在上课.....")
    
        def sayHI(self):
            # print("hello 我是%s 今年%s岁 性别:%s" % (self.name,self.age,self.sex))
            # 访问父类中的方法来简化代码
            # 指名道姓
            # Person.sayHI(self)
            super().sayHI()
            print("学号:",self.number)
    
    stu1 = Student("阿三",20,"woman","9527")
    # print(stu1)
    # print(stu1.name,stu1.age,stu1.sex)
    stu1.sayHI()
    
    # super一定用在 存在继承关系的子类中
    字类访问父类的方法
    存在继承关系的查找方法
    #
    # class E:
    #     a = 5
    #
    # class A(E):
    #     a = 4
    #     pass
    #
    # class B:
    #     a = 3
    #     pass
    #
    # class C:
    #     a = 2
    #     pass
    #
    # class D(A,B,C):
    #     # a = 1
    #     pass
    #
    # d1 = D()
    # # d1.a = 10
    # print(d1.a)
    
    #按照继承的顺序,从左到右
    
    
    所有直接继承或间接继承object的类 都是新式类
    object 称之为根类 意思是 所有类 都源自于object类
    为什么这么设计?
    例如:创建对象时,需要申请内存空间,创建新的名称空间,将对象的属性放入名称空间,这一些了复杂的基础操作,都有object来完成
    简单地说object提供了一些常用的基础操作
    即所有类都属于新式类(在python3中)

    在python3中默认所有类都是新式类

    而python2中默认是经典类(不会自动继承Object)

    class A:
        age = 18
    
        def f1(self):
            print(" A f1"
            )
        pass
    class B(A):
        age1 = 19
        def f1(self):
            self.f1()
            print(" B f1")
    
        pass
    
    b1 = B()
    print(b1.age)
    
    b1.f1()
    
    # 子类出现了与父类重复的名字 称之为覆盖
    # 子类出现了与父类不同的名字 称之为拍派生
    覆盖
    host = '127.0.0.1'
    port = 3306
    db = 'db1'
    charset = "utf-8"
    
    #1、在没有学习类这个概念时,数据与功能是分离的
    def exc1(host,port,db,charset,sql):
        conn=connect(host,port,db,charset)
        conn.execute(sql)
        return 123
    
    
    def exc2(host,port,db,charset,proc_name):
        conn=connect(host,port,db,charset)
        conn.call_proc(proc_name)
        return 123
    
    
    def exc2(host,port,db,charset,proc_name):
        conn=connect(host,port,db,charset)
        conn.call_proc(proc_name)
        return 123
    #每次调用都需要重复传入一堆参数
    # exc1('127.0.0.1',3306,'db1','utf8','select * from tb1;')
    #
    # exc2('127.0.0.1',3306,'db1','utf8','存储过程的名字')
    
    
    
    # exc1(host,port,db,charset,"select * from tb1")
    # exc2(host,port,db,charset,"过程名称")
    
    class Mysql:
    
        def __init__(self,host,port,db,charset):
            self.host = host
            self.port = port
            self.db = db
            self.charset = charset
    
        def exc2(self,proc_name):
            conn=connect(self.host,self.port,self.db,self.charset)
            conn.call_proc(proc_name)
            return 123
    
        def exc1(self,sql):
            conn=connect(self.host,self.port,self.db,self.charset)
            conn.execute(sql)
            return 123
    
    
    my1 = Mysql("127.0.0.1",3306,"mydb","utf-8")
    
    my1.exc1("select *from table1")
    my1.exc2("名字")
    
    
    #  精髓 是 将数据和处理数据的代码绑定 成了一个对象
    #  只要获取到对象 相应的数据和方法都有了
    面向对象的精髓
    组合
    多个对象放在一起叫组合

    组合 也可以降低代码的冗余
    
    
    # 学生会增加各种各样的新的属性  比如手机  比如电脑, 这样Student中会增加大量的属性和方法
    # 后期的维护成本非常高
    # 这时就需要使用组合 来完成减少代码冗余
    
    class Phone:
        def __init__(self,phonenumber,operator,address):
            self.phonenumber = phonenumber
            self.operator = operator
            self.address = address
    
        def call(self):
            print("%s 正在拨号" % self.phonenumber)
    
    
    class Person:
        def __init__(self,name,sex,age):
            self.name = name
            self.sex = sex
            self.age = age
    
    
    class Student(Person):
        def __init__(self,name,sex,age,number):
            super().__init__(name, sex, age)
            self.number = number
    
        def show_info(self):
            # print("name:%s sex:%s, age:%")
            print(self.__dict__)
    
        def select_cursor(self):
            print("%s 正在选课...." % self.name)
    
    class Teacher(Person):
        def __init__(self,name,sex,age,salary,level):
            super().__init__(name,sex,age)
            self.salary = salary
            self.level = level
        def set_score(self):
            print("%s 正在为学生打分..." % self.name)
    
    
    stu = Student("乔峰","",38,"007")
    
    # 学生买了一台手机 所以增加一个手机属性
    p1 = Phone("1999999999","中国小米移动","上海浦东")
    
    stu.phone = p1
    
    # 学生要打电话
    stu.phone.call()
    
    # 通过将手机对象和学生对象进行组合  完成了需求,并且相比较继承而言
    # 耦合度低  手机和学生在修改的时候 互不影响
    # 同时也减少了代码冗余
    
    # 继承是一种关系  什么是什么   学生是人类  老师是人类    (如果把手机相关内容插入到人类中,相当于学生是手机???)
    # 组合是 对象之间的关系   学生对象拥有手机对象
    组合
    面向对象三大特征之封装
    1.什么是封装

    生活中的封装 类似工厂 拿个纸箱,装入一堆产品,拿胶带封起来
    在程序中,封装指的是将内容隐藏起来, 在面向对象中有什么内容可以被隐藏?,就是属性和方法

    注意:封装绝不是单纯的隐藏
    封装是指,隐藏内部实现细节,对外提供使用接口

    2.为什么要封装
    1.提高安全性 (例如:cpu频率 缓冲区大小,电脑,手机,汽车,收音机)
    对于封装属性而言,是通过给访问和修改增加额外的逻辑判断来实现的
    对于封装方法
    2.封装是为了明确区分内部和外部



    3.如何使用封装
    在属性或方法名称前 加上两个下划线,就可以将其设置为私有的
    另外补充: python中权限只有两种,公开(谁都能访问)的和私有(只有自己能访问)的
    属性的封装,通过需要提供相应的设置器和访问器

    4.什么时候用
    5.封装的实现原理

    6.封装的特点
    被隐藏的内容 在内部是可以直接访问,外部无法访问
    class Student:
        def __init__(self,name,sex,age,idCard):
            self.name = name
            self.age = age
            self.sex = sex
            self.__idCard = idCard
        def say_hi(self):
            print("hello i am %s age is : %s sex is %s" %
                  (self.name,self.age,self.sex))
    
        def test(self):
            print(self.__idCard)
    
        # 可以使用方法 将内部封装的内容返回出去
        def get_idCard(self):
            return self.__idCard
    
        # 如果直接返回的话 就没必要设置隐藏了 ,谁都可以通过调用方法来获取,我们再方法中加上自己的判断逻辑
        def get_idCard2(self,pwd): # 如果密码正确我就给你身份证号码
            if pwd == "1111":
                return self.__idCard
            else:
                print("滚 你没有资格知道我的身份证...")
    
        def set_idCard(self,pwd,new_idCard): # 如果密码正确就允许修改
            if pwd == "1111":
                self.__idCard = new_idCard
            else:
                print("滚 你没有资格修改我的身份证...")
    
    
    
    
    
    stu = Student("步惊云","",20,"3206661998445132")
    stu.say_hi()
    
    # print(stu.__idCard)  # 加上__也访问不了
    
    # stu.test() # 但在内部是可以访问的
    
    # idcard = stu.get_idCard()
    # print(idcard)
    # 即实现了隐藏  又提供了访问的接口 这就是封装的用法
    # idcard = stu.get_idCard2("1111")
    # print(idcard)
    
    
    # 身份证填错了 要修改
    # stu.__idCard = "123" # 这样是无法修改原来的身份证信息的 而是添加了新的属性
    #
    # print(stu.__idCard)
    # print(stu.get_idCard2("1111"))
    
    # 调用方法来修改隐藏的属性
    stu.set_idCard("1111","xxxxxxxxxxxxxxxxxx")
    
    print(stu.get_idCard2("1111"))
    
    
    # 总结:对于被隐藏的属性  访问和修改都需要通过方法 get用于获取  set用于设置(也称之为设置器和访问器)
    封装
    class A:
    
        def __f1(self):
            print("f1 run")
    
        def run_f1(self):
            self.__f1()
    
    a = A()
    a.run_f1()
    
    
    
    
    # ATM 的取款功能
    # 1.插入银行卡 2.输入密码 3.选择取款金额  4.取款
    
    class ATM:
        def __insert_card(self):
            print("插入银行卡...")
    
        def __input_pwd(self):
            print("输入密码...")
        def __select_money(self):
            print("选择取款金额...")
        def withdraw(self):
            self.__insert_card()
            self.__input_pwd()
            self.__select_money()
            print("取款成功!....")
    
    atm = ATM()
    
    atm.withdraw() # 外部调用这个简单的接口 就能完成一系列复杂的操作
    
    # atm.select_money()  #直接调用内部的方法 是没有意义的无法完成整个功能
    
    # 当然用户按照流程一一调用也可以完成功能 但是太麻烦
    # atm.insert_card()
    # atm.input_pwd()
    # atm.select_money()
    
    # 封装方法 如何封装 给方法名字前面加上双下划线
    # 封装方法的好处:
    # 1.提高安全性
    # 2.隔离复杂度  (将复杂的内容隔离到内部 外部只留下简单的接口 对于使用者 难度降低)
    封装方法
    class Person:
    
        def __init__(self,name,sex,age,idCard):
            self.name = name
            self.sex = sex
            self.__age = age
            self.__idCard = idCard
    
        def get_idCard(self):
            return self.__idCard
    
        def __test(self):
            pass
    
        print("aaaaaaaaaa")
    
    
    # p = Person("比尔盖茨","男",20,"322323232332332")
    #
    # # print(p.__idCard)
    # p.__idCard = "XXXXXX"
    # print(p.__idCard)
    #
    # print(p.get_idCard())
    #
    # print(p.__dict__)
    # print(Person.__dict__)
    #
    #
    # p.__xxxxxxxxxxxx = 1
    #
    # print(p.__dict__)
    
    
    # 通过__dict__ 可以发现
    # 1.私有的属性和方法名称 前自动加上了_类名 python就是通过这样的转换方式来实现封装
    # 2.只有在类的内部的双下划线才会被自动转换,并且这个转换过程只执行一次,在类定义完成后 后续添加的双下划线开头的名称是不会自动转换的
    # 3.父类中私有的方法 子类中无法使用
    
    
    #在父类中定义的私有方法 能不能被子类所覆盖?
    
    
    # class A:
    #     def __f1(self):
    #         print("A __f1")
    #
    # class B(A):
    #     def __f2(self):
    #         # self.__f1()
    #         super().__f1()
    #         print("B __f2")
    #
    #     def test(self):
    #         self.__f2()
    #
    # b = B()
    # b.test()
    
    
    
    
    # 子类无法覆盖父类的私有方法
    
    # class  A:
    #     def f(self):
    #         self.__f1()   #_A__f1
    #
    #     def __f1(self):
    #         print("A  __f1")
    #
    # class B(A):
    #     def __f1(self):  # _B__f1
    #         print("B __f1")
    #
    #     def f2(self):
    #         self.f()
    #
    # b = B()
    # b.f2()
    
    # 之所以无法覆盖 是因为 子类和父类中的私有方法 名称必然不相同 所以无法覆盖   子类的方法一定子类独有的 因为名称不同
    
    
    
    
    class A:
        __age = 10
    
    # 绕过封装的限制直接访问  这是毫无意义的
    print(A._A__age)
    封装的实现原理
    
    
    当一些属性的值 不是固定的而是通过计算得来的时候  我们必须为这个属性增加方法才能完成计算
    但是一旦使用方法后 该属性的访问就变成了方法的调用 很明显与其他的属性访问方式不同,这样给使用者造成迷惑
    所以需要将这个方法伪装成普通属性 这就用到了Property

    property可以将方法伪装成属性 利用这个特点 我们也可以将其使用到封装中
    之前没有这个装饰器我们需要为私有的属性 提供两个方法 但是这样一来方位私有属性时的方式就发生了变化
    这时候就可以使用property来进行伪装 使得访问私有属性与访问普通属性的方式一致

    另外 property还提供了 setter(用于修改属性的值) 和 deleter(删除属性的值)
    # BIM案例:
    class Person:
        def __init__(self,name,weight,height):
            self.name = name
            self.weight = weight
            self.height = height
            # self.bmi = weight/(height*height)
        # def bmi(self):
        #     return self.weight / (self.height * self.height)
        @property
        def bmi(self):
            return self.weight / (self.height * self.height)
    
    p = Person("尔晴",50,1.5)
    # print(p.bmi)
    # p.weight = 90
    # print(p.bmi)
    
    # 现在 虽然可以实现需求 但是我们把一个属性变成了一个行为 这是不合理的
    # print(p.bmi())
    # p.weight = 90
    # print(p.bmi())
    
    # 使用property装饰器 可以将一个方法伪装成一个属性
    print(p.bmi)
    p.height += 0.2
    print(p.bmi)
    
    
    class Student:
        def __init__(self,name,sex,idCard):
            self.name = name
            self.sex = sex
            self.__idCard = idCard
    
        def get_idCard(self):
            return self.__idCard
    
        def set_idCard(self,new_id):
            self.__idCard = new_id
    
        @property # 需要掌握
        def idCard(self):
            return self.__idCard
    
    
        @idCard.setter #了解的
        def idCard(self,new_id):
            self.__idCard = new_id
    
        @idCard.deleter # 了解的
        def idCard(self):
            print("身份证属性被删除了.....")
            del self.__idCard
    
    
    stu = Student("尔康","","323254554554")
    
    # print(stu.get_idCard())
    
    # stu.set_idCard("xxxx")
    
    print(stu.get_idCard()) # 使用装饰器前
    print(stu.name) # 普通属性的访问
    
    print(stu.idCard) # 使用装饰器后
    
    stu.idCard = "aaaaaaa" # 使用装饰器后的修改操作
    
    print(stu.idCard)
    
    del stu.idCard
    
    print(stu.__dict__)
    print(Student.__dict__)
    peoperty
    多态
    什么是多态
    多种状态 形态
    生活中具备多种形态的事物 水(水蒸气,冰,液态水) 奥特曼(红色 力量,蓝色 速度) 数码宝贝(究极形态)
    一种事物 具备多种形态或状态 就称之为多态
    官方解释:不同对象 可以相应同一方法,并作出不同的行为,产生不同结果

    如何实现多态?
    让几个不同类拥有相同父类,这样一来他们就具备了相同的方法,每个子类要覆盖父类的方法,从而每个类的对象行为都不同

    程序中的多态,例如动物

      
    class Animal:
        def eat(self):
            print("动物在吃东西...")
        def sleep(self):
            print("动物在睡觉...")
        def drink(self):
            print("动物需要水.....")
    
    
    class Person(Animal):
        def eat(self):
            print("人吃粮食...")
    
    class Pig(Animal):
        def eat(self):
            print("猪吃饲料...")
    
    class Dog(Animal):
        def eat(self):
            print("狗吃骨头...")
    
    
    person = Person()
    pig = Pig()
    dog = Dog()
    
    person.eat()
    pig.eat()
    dog.eat()
    
    #假设你学习了C1驾照  意味着 所有C1类的汽车都能开  因为每种C1汽车的驾驶方式相同
    
    
    # 当使用了多态之后 对象的使用者不需要关系这个对象具体的实现,只需要知道该对象属于哪个基类,就能直接使用它
    # 如此扩展性变高了
    
    
    class Phone:
        def call(self):
            print("手机就能打电话..")
    
        def send_msg(self):
            print("手机能发短信..")
    
    
    class WindowsPhone(Phone):
        def call(self):
            print("拨号打电话..")
    
        def send_msg(self):
            print("输入号码发短信..")
    
    class IPhone(Phone):
        def call(self):
            print("拨号打电话..")
    
    
        def send_msg(self):
            print("输入号码发短信..")
    
    
    
    
    # 可以定义一个方法接受一个手机为参数 无论是是类型的手机 都可以被使用
    
    def CALL(phone):
        phone.call()
    
    wp = WindowsPhone()
    ipx = IPhone()
    
    CALL(wp)
    CALL(ipx)
    
    
    # 系统内置的方法有很多都体现了多态
    
    
    print(len("abc"))
    print(len([1,2,3,4,]))
    print(len({"name":"123","sex":"man"}))
    
    print("abc".__len__())
    print([1,2,3,4,].__len__())
    print({"name":"123","sex":"man"}.__len__())
    
    print(len({1,23,4,5}))
    """
        多态是多个类的对象拥有相同的方法,但是我们没有从严格要求说必须提供这些方法,子类完全可以不提供这些方法
        # 现在要做的就是 严格要求 子类必须实现父类声明的方法
    
    """
    
    import abc
    # abstract class 是抽象类的缩写   抽象的意思是 不清晰 不具体 看不懂
    
    #使用ABC模块来限制子类 的步骤
    #1.为类中指定元类为abc.ABCMeta
    #2.在相应的方法上加上abc.abstractmethod装饰器
    
    class Animal(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod
        def eat(self):
            pass
    
        @abc.abstractmethod
        def drink(self):
            pass
    
    
    class Cat(Animal):
        def eat(self):
            print("猫爱吃鱼肉...")
    
        def drink(self):
            print("用舌头舔..")
    
    class Dog(Animal):
        def eat(self):
            print("狗爱吃骨头...")
        def drink(self):
            print("用舌头舔..")
    
    class Pig(Animal):
        def eat(self):
            print("猪 爱吃草...")
    
        def drink(self):
            print("用嘴吸的..")
    
    p = Pig()
    # p.eat()
    
    c = Cat()
    # c.eat()
    
    # 多态的好处 完全不需要考虑得到的对象时声明类型 只要知道了其基类中的内容就能使用
    def feeding(animal):
        animal.eat()
        animal.drink()
    
    feeding(c)
    feeding(p)
    # 多态中的基类 相当于(协议 标准 规范) 要求子类必须满足这些标准
    多态abc模块
    class Duck:
    
        def bark(self):
            print("鸭子嘎嘎叫...")
    
        def run(self):
            print("摇摇晃晃走....")
    
    class Chicken:
        def bark(self):
            print("鸡咯咯叫...")
    
        def run(self):
            print("摇摇晃晃走....")
    
    def test(obj):
        obj.bark()
        obj.run()
    duck = Duck()
    c = Chicken()
    
    test(duck)
    test(c)
    
    # 如果你足够自觉 你可以不使用abc模块 也不需要基类 自觉地将方法名字都写成一样 同样可以实现多态
    # 这种方式称之为鸭子类型
    鸭子类型





  • 相关阅读:
    从头编写 asp.net core 2.0 web api 基础框架 (1)
    希腊字母表
    Python数据分析(二): Numpy技巧 (4/4)
    Python数据分析(二): Numpy技巧 (3/4)
    Python数据分析(二): Numpy技巧 (2/4)
    OLED液晶屏幕(3)串口读取文字并分割
    OLED液晶屏幕(2)取模软件
    OLED液晶屏幕(0)自动获取12ic地址液晶屏幕
    OLED液晶屏幕(1)OLED液晶屏幕ssd1306驱动芯片 arduino运行 ESP8266-07可以 12f不可以
    I2C 连接 12864 OLED 屏幕
  • 原文地址:https://www.cnblogs.com/BestSkye/p/10115740.html
Copyright © 2011-2022 走看看