美文网首页
类,封装

类,封装

作者: 慕知 | 来源:发表于2021-09-06 18:26 被阅读0次

    一,面向对象

    面向过程:
    优点:复杂的过程流程化,简单化
    缺点:可扩展性差
    举例:linux中shell编译安装,这种固定的流程,面向过程方式堆积命令即可
    
    
    面向对象:对象是特征与技能的合体
    优点:可扩展性强
    缺点:编程复杂难度高,容易出现过度设计
    
    
    
    
    

    二,类

    1,类的定义

    
    在程序中:一定先有类再有对象
    对象可以访问到类中共有的数据与功能,所以类中的内容仍然是属于对象的;
    类只不过是一种节省空间、减少代码冗余的机制,面向对象编程最终的核心仍然是去使用对象。
    
    
    
    class Student:
        beauty='mzz'
        def learning(self):
            print('mzz like to study')
        print('----->running')
    
    # ----->running会在"类"定义阶段执行
    
    # 查看类的内存空间
    print(Student.__dict__)
    # {'__module__': '__main__', 'beauty': 'mzz', 'learning': <function Student.learning at 0x102c43e50>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
    
    
    
    
    print(Student.beauty)    # 数据类型(变量)
    # mzz
    print(Student.learning)     # 函数属性
    # <function Student.learning at 0x103063e50>
    # 类调用的learning是一个函数,所以要按照函数的调用方式,即要加上self这个参数
    
    Student.learning('mzz')
    # ----->running
    # mzz like to study
    
    
    
    
    
    
    
    
    # 增加
    Student.counry="China"
    print(Student.counry)
    # China
    
    
    # 修改
    Student.beauty="Egg"
    print(Student.beauty)
    # Egg
    
    
    # 删除
    del Student.counry
    #print(Student.counry) # 会报错,已经删除
    
    # 查看类的内存空间验证,没有country
    print(Student.__dict__)
    
    

    2,类的实例化过程

    # 调用类的过程又称实例化
    #1)得到一个返回值,即对象,该对象是一个空对象
    #2) Student.__init__,把类当作第一个参数传进去
    class Student:
        beauty='mzz'
    
        def __init__(self,name,age,sex):  # 在调用时自动触发
            self.Name=name
            self.Age=age
            self.Sex=sex
    
        def learning(self):
            print('mzz like to study')
    
    
    s1=Student('mz',13,'female')
    print(s1.__dict__)
    # {'Name': 'mz', 'Age': 13, 'Sex': 'female'}
    
    print(s1.Sex)
    # female
    
    
    s2=Student('egon',22,'male')
    print(s2.Name)
    # egon
    
    
    

    3,属性查找与绑定方法

    #1, 查找一个对象的属性,先找自己的__dict__,再找类的__dict__
    class Student:
        school='Asia'
    
        def __init__(self,name,age,sex):  # 在调用时自动触发
            self.Name=name
            self.Age=age
            self.Sex=sex
    
        def learning(self):
            print('%s like to study' %self.Name)
    
    s1=Student('mz',13,'female')
    s2=Student('egon',22,'male')
    
    
    
    
    
    #2, 类的数据属性是所有对象共享,所有对象都指向同一个内存地址
    print(Student.school,id(s1.school))
    # Asia 4303951152
    print(Student.school,id(s2.school))
    # Asia 4303951152
    
    
    
    Student.school='India'
    print(Student.school,id(s1.school))
    # India 4383185008
    print(Student.school,id(s2.school))
    # India 4383185008
    
    
    
    
    
    
    
    
    
    #3, 类中定义的函数是绑定给对象使用,类也可以使用(用起来会很复杂)
    # 不同对象就是不同绑定方法
    # 绑定给谁,就应该给谁调用
    
    print(Student.learning)
    # <function Student.learning at 0x10029f790>
    print(s1.learning)
    # <bound method Student.learning of <__main__.Student object at 0x10025dfa0>>
    print(s2.learning)
    # <bound method Student.learning of <__main__.Student object at 0x1002962b0>>
    
    
    s1.learning()
    # mz like to study
    s2.learning()
    # egon like to study
    
    
    
    
    
    
    # 接上验证,函数属性的绑定方法
    class Student:
        school='Asia'
    
        def __init__(self,name,age,sex):  # 在调用时自动触发
            self.Name=name
            self.Age=age
            self.Sex=sex
    
        def learning(self,x,y):
            print('%s like to study' %self.Name)
            print(x,y)
    
    
    s1=Student('mz',13,'female')
    s2=Student('egon',22,'male')
    
    s1.learning(1,2)
    # mz like to study
    # 1 2
    
    
    s2.learning(1,2)
    # egon like to study
    # 1 2
    
    
    #类也可以使用(用起来会很复杂)
    Student.learning(s1,1,2)
    # mz like to study
    # 1 2
    
    
    
    类的函数属性调用默认必须要有一个参数
    
    

    示例

    # 示例:任何一个老师都可以看到老师的个数
    class Teacher:
        school='Asia'
        count=0
    
        def __init__(self,name,sex,age,level,salary):
            self.name=name
            self.age=age
            self.level=level
            self.salary=salary
            Teacher.count+=1
    
        def teach(self):
            print('%s is teaching' %self.name)
    
    
    t1=Teacher('小艾','male',20,1,3000)
    t2=Teacher('小林','male',21,2,4000)
    t3=Teacher('小狗','female',23,3,5000)
    
    
    # 查看Teacher数量
    print(t1.count)
    print(t2.count)
    print(t3.count)
    # 3   都是3
    
    

    4,类和对象

    a1=list([1,2,3,4])
    a2=list([1,2,3,4])
    print(id(a1))
    # 4343027392
    
    print(id(a2))
    # 4343027456
    
    a1.append('a')
    a2.append('b')
    
    print(a1)
    # [1, 2, 3, 4, 'a']
    
    print(a2)
    # [1, 2, 3, 4, 'b']
    
    python中,一切皆对象,类型本质都是类。
    数据类型都是一个个类创造的对象
    
    

    -- 游戏中生命值攻击力示例

    class Dog:
        camp='A' #所有类里面的(xiaohua)都属于A组
        def __init__(self,name,life_value=200,attack_value=10):
        # 初始生命值200,初始攻击力10
            self.name=name
            # 赋值,前面的name可以任意起名
            self.life_value=life_value
            self.attack_value=attack_value
        def attack(self,enemy):   # 攻击技能
            enemy.life_value-=self.attack_value
            # 敌人的生命力=敌人的生命力减去自己的攻击力
    
    class Cat:
        camp='B'
        def __init__(self,name,life_value=100,attack_value=80):
            self.name=name
            self.life_value=life_value
            self.attack_value=attack_value
        def attack(self,enemy):
            enemy.life_value-=self.attack_value
    
    xiaohua=Dog('xiaohua')
    mimi=Cat('mimi')
    
    
    print(xiaohua.life_value)
    # 200
    
    mimi.attack(xiaohua)
    print(xiaohua.life_value)
    # 120
    
    

    5,代码级别看面向对象

    # 伪代码示例
    
    #1、在没有学习类这个概念时,数据与功能是分离的
    def exc1(host,port,db,charset):
        conn=connect(host,port,db,charset)
        conn.execute(sql)
        return xxx
    
    
    def exc2(host,port,db,charset,proc_name):
        conn=connect(host,port,db,charset)
        conn.call_proc(sql)
        return xxx
    
    #每次调用都需要重复传入一堆参数
    exc1('127.0.0.1',3306,'db1','utf8','select * from tb1;')
    exc2('127.0.0.1',3306,'db1','utf8','存储过程的名字')
    
    
    
    #2、我们能想到的解决方法是,把这些变量都定义成全局变量
    HOST=‘127.0.0.1’
    PORT=3306
    DB=‘db1’
    CHARSET=‘utf8’
    
    def exc1(host,port,db,charset):
        conn=connect(host,port,db,charset)
        conn.execute(sql)
        return xxx
    
    
    def exc2(host,port,db,charset,proc_name)
        conn=connect(host,port,db,charset)
        conn.call_proc(sql)
        return xxx
    
    exc1(HOST,PORT,DB,CHARSET,'select * from tb1;')
    exc2(HOST,PORT,DB,CHARSET,'存储过程的名字')
    
    
    
    
    
    #3、但是2的解决方法也是有问题的,按照2的思路,我们将会定义一大堆全局变量,这些全局变量并没有做任何区分,即能够被所有功能使用,然而事实上只有HOST,PORT,DB,CHARSET是给exc1和exc2这两个功能用的。言外之意:我们必须找出一种能够将数据与操作数据的方法组合到一起的解决方法,这就是我们说的类了
    
    class MySQLHandler:
        def __init__(self,host,port,db,charset='utf8'):
            self.host=host
            self.port=port
            self.db=db
            self.charset=charset
        def exc1(self,sql):
            conn=connect(self.host,self.port,self.db,self.charset)
            res=conn.execute(sql)
            return res
    
    
        def exc2(self,sql):
            conn=connect(self.host,self.port,self.db,self.charset)
            res=conn.call_proc(sql)
            return res
    
    
    

    三,封装

    1,隐藏属性

    # 正常情况下,x可以通过调用Foo正常访问
    class Foo:
        x=1
    
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
    print(Foo.x)
    # 1
    
    abc=Foo('dog',3)
    print(abc.age)
    # 3
    
    
    
    
    
    # 隐藏属性,在需要隐藏属性的前面加上__(两个下划线)
    # 隐藏属性是在调用阶段生成,所以在类内部是可以直接访问双下滑线开头的属性的
    class Foo:
        __x=1
    
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
    
    #print(Foo.x)  会报错
    
    obj=Foo('mzz',18)
    print(obj.name,obj.age)
    # mzz 18
    
    
    
    class Foo:
        __x=1
    
        def __init__(self,name,age):
            self._name=name
            self._age=age
    
    print(Foo.__dict__)
    # {'__module__': '__main__', '_Foo__x': 1, '__init__': <function Foo.__init__ at 0x10304f790>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
    
    # 根据属性的变形,通过以下方式可以得到隐藏的属性的值
    print(Foo._Foo__x)
    # 1
    
    
    

    2,为什么使用隐藏属性

    
    
    
    class People:
        def __init__(self,name):
            self.__name=name
    
    
    
    #People.get_name('mmm')   # 会报错
    
    obj=People('muzz')
    #print(obj.set_name())   # 会报错
    
    
    class People:
        def __init__(self,name):
            self.__name=name
    
        def get_name(self):
            # 类似于开个接口,可以赋予其他的东西
            print('谁是小可爱')
            print(self.__name)
    
    obj=People('muzz')
    obj.get_name()
    # 谁是小可爱
    # muzz
    
    
    # 类的创造者,可以严格控制使用者对属性的操作
    class People:
        def __init__(self,name):
            self.__name=name
    
        def get_name(self):
            # 类似于开个接口,可以赋予其他的东西
            print('不给看')
    
    obj=People('muzz')
    obj.get_name()
    # 不给看
    
    
    
    # 如果更改名字,如下
    class People:
        def __init__(self,name):
            self.__name=name
    
        def get_name(self):
            print(self.__name)
    
        def set_name(self,val):
            self.__name=val
    
    obj=People('muzz')
    obj.set_name('egon')
    obj.get_name()
    # egon
    
    
    
    
    
    # 增加条件
    class People:
        def __init__(self,name):
            self.__name=name
    
        def get_name(self):
            print(self.__name)
    
        def set_name(self,val):
            if type(val) is not str:
                print('必须字符串类型')
                return
            self.__name=val
    
    obj=People('muzz')
    obj.set_name(12235)
    obj.get_name()
    # 必须字符串类型
    # muzz
    
    
    

    3,property装饰器

    1)用法一
    """
    成人的BMI数值:
    过轻:低于18.5
    正常:18.5-23.9
    过重:24-27
    肥胖:28-32
    非常肥胖, 高于32
      体质指数(BMI)=体重(kg)÷身高^2(m)
      EX:70kg÷(1.75×1.75)=22.86
    """
    
    
    # 例1:传值给People,得到ami的值需要obj.ami(),即调用函数的方式
    class People:
        def __init__(self,name,weight,height):
            self.name=name
            self.weight=weight
            self.height=height
    
        def ami(self):
            print(self.weight / (self.height **2))
    
    obj=People('mzz',55,1.70)
    print(obj.ami())
    # 19.031141868512112
    # None
    
    obj.ami()
    # 19.031141868512112
    
    
    
    
    
    
    # 例2:加上@property 可以正常以obj.ami方式调用
    class People:
        def __init__(self,name,weight,height):
            self.name=name
            self.weight=weight
            self.height=height
    
        @property
        def ami(self):
            print(self.weight / (self.height **2))
    
    obj=People('mz',55,1.70)
    obj.ami
    # 19.031141868512112
    
    
    
    2)用法2
    # property用法2
    class People:
        def __init__(self, name):
            self.__name = name
    
        def get_name(self): # obj1.name
            return self.__name
    
        def set_name(self, val): # obj1.name='EGON'
            if type(val) is not str:
                print('必须传入str类型')
                return
            self.__name = val
    
        def del_name(self): # del obj1.name
            del self.__name
    
        name=property(get_name,set_name,del_name)
    
    obj=People('eggg')
    print(obj.name)
    
    obj.set_name('EGGG')
    print(obj.name)
    #EGGG
    
    obj.del_name()
    print(obj.name) # 会报错
    
    
    3) 用法3 (建议)
    # property用法3
    class People:
        def __init__(self, name):
            self.__name = name
    
        @property
        def name(self): # obj1.name
            return self.__name
    
        @name.setter
        def name(self, val): # obj1.name='EGON'
            if type(val) is not str:
                print('必须传入str类型')
                return
            self.__name = val
    
        @name.deleter
        def name(self): # del obj1.name
            print('不让删除')
    obj=People('mz')
    print(obj.name)
    # mz
    
    obj.name=12
    # 必须传入str类型
    
    obj.name='xiaohua'
    print(obj.name)
    # xiaohua
    
    del obj.name
    # 不让删除
    
    
    
    
    注意def name的name要统一
    

    相关文章

      网友评论

          本文标题:类,封装

          本文链接:https://www.haomeiwen.com/subject/ummxwltx.html