• 自学Python5.7-面向对象三大基本特征_封装


    自学Python之路-Python基础+模块+面向对象
    自学Python之路-Python网络编程
    自学Python之路-Python并发编程+数据库+前端
    自学Python之路-django

    自学Python5.7-面向对象三大基本特征_封装

    一、封装

    1.1  封装概念

    广义上面向对象的封装 :代码的保护,面向对象的思想本身就是一种封装,只让自己的对象调用自己的方法。

    狭义上的封装:面向对象的三大基本特征之一,隐藏对象的属性和实现细节,仅对外提供公共访问方式。

    封装的好处: 

    • 将变化隔离; 
    • 便于使用;
    • 提高复用性; 
    • 提高安全性;

    封装原则:

    • 将不需要对外提供的内容都隐藏起来;
    • 把属性都隐藏,提供公共方法对其访问。
    class Person:
        def __init__(self,name,passwd):
            self.name = name
            self.passwd = passwd
    carlos = Person("carlos","carlos7628")
    print(carlos.passwd)  # 打印出carlos的密码
    

    1.2  私有属性

    1.2.1  私有属性,在外部调用不到

    # 若不想别人查看carlos的密码
    class Person:
        def __init__(self,name,passwd):
            self.name = name
            self.__passwd = passwd   #加上"__",隐藏属性,----私有属性
    carlos = Person("carlos","carlos7628")
    print(carlos.__passwd)

    1.2.2  私有属性,使用一种方法可以在外部调用(通常不使用)

    class Person:
        def __init__(self,name,passwd):
            self.name = name
            self.__passwd = passwd   #加上"__",隐藏方法
    carlos = Person("carlos","carlos7628")
    print(carlos.__dict__)  # 查看属性里面都有什么
    

    此时查看到密码的真实属性是“_Person__passwd'”, 再来print一下:

    class Person:
        def __init__(self,name,passwd):
            self.name = name
            self.__passwd = passwd   #加上"__",隐藏方法
    carlos = Person("carlos","carlos7628")
    print(carlos._Person__passwd)  # _类的名字__属性的名字,就能查看到私有属性的内容
    

    1.2.3  私有属性,只要在类的内部使用私有属性,就会自动的转换成带上_类名

    class Person:
        def __init__(self,name,passwd):
            self.name = name
            self.__passwd = passwd   #加上"__",隐藏方法 ,
        def get_pwd(self):
            return self.__passwd    #只要在类的内部使用私有属性,就会自动的转换成带上_类名。 就是_Person__passwd
    carlos = Person("carlos","carlos7628")
    print(carlos._Person__passwd)
    print(carlos.get_pwd())
    

    1.2.4  只要在类的内部使用私有属性,就会自动的转换成带上_类名,就是_Person__passwd。但是在类的外部不是的。

    class Person:
        def __init__(self,name,passwd):
            self.name = name
            self.__passwd = passwd   #加上"__",隐藏方法
        def get_pwd(self):
            print(self.__dict__)
            return self.__passwd    #只要在类的内部使用私有属性,就会自动的转换成带上_类名
    carlos = Person("carlos","carlos7628")
    print(carlos._Person__passwd)
    carlos.__high = 181
    print(carlos.get_pwd())
    print(carlos.__high)
    

    举例:

    # 定一个房子类, 计算面积
    class Room:
        def __init__(self,name,length,width):
            self.name = name
            self.__length = length     #私有属性
            self.__width = width       #私有属性
        def area(self): 
            return self.__length * self.__width
    Tong = Room('Tong',2,1)
    print(Tong.area())

    现在有个问题,如果更改name,使用方法如下:

    class Room:
        def __init__(self,name,length,width):
            self.name = name
            self.__length = length
            self.__width = width
        def area(self):
            return self.__length * self.__width
    Tong = Room('Tong',2,1)
    print(Tong.area())
    Tong.name = "Carlos"
    print(Tong.name)
    

    最好的解决办法如下,name采用私有属性。 (对私有属性的保护,不可以随便更改名字name)

    class Room:
        def __init__(self,name,length,width):
            self.__name = name
            self.__length = length
            self.__width = width
        def get_name(self):
            return self.__name
        def set_name(self,newName):
            if type(newName) is str and newName.isdigit() == False:   # 非数字的字符串
                self.__name = newName
            else:
                print('不合法的姓名')
        def area(self):
            return self.__length * self.__width
    Tong = Room('Tong',12,6)
    print(Tong.area())       # 打印tong房子的面积
    Tong.set_name("carlos")  # 设置名字为carlos
    print(Tong.get_name())    
    Tong.set_name("2")     # 设置了非法的名字2
    print(Tong.get_name())
    

    1.2.5 父类的私有属性不能被子类调用

    # 父类的私有属性不能被子类调用
    class Foo:
        __key = '123'       # _Foo__key   静态私有属性
    
    class Son(Foo):
        print(Foo.__key)     # _Son__key
    

    1.3  私有方法

    class Person:
        def __init__(self,name,passwd):
            self.name = name
            self.__passwd = passwd   #加上"__",隐藏方法
        def __get_pwd(self):         #私有方法
            return self.__passwd    #只要在类的内部使用私有属性,就会自动的转换成带上_类名
        def login(self):          # 正常的方法调用私有的方法
            self.__get_pwd()

    1.4  总结

    • # 所有的私有 都是在变量的左边加上双下划綫
    •    对象的私有属性
    •    类中的私有方法
    •    类中的静态私有属性
    • # 所有的私有的 都不能在类的外部使用
    • # 采用私有概念的场景:①隐藏起一个属性 ,不想让类的外部调用;②我想保护这个属性,不想让属性随意被改变;③我想保护这个属性,不被子类继承

    、property内置函数

    property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值。

    举例1: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,weight,height):
            self.name=name
            self.weight=weight
            self.height=height
        @property
        def bmi(self):
            return self.weight / (self.height**2)
    p1=People('carlos',75,1.85)
    print(p1.bmi)  # @Property直接调用属性bmi====== 没有Property调用方法bmi()
    

    举例2: 圆的面积和周长

    from math import pi
    class Circle:
        def __init__(self,r):
            self.r = r
        def permeter(self):
            return 2*pi*self.r
        def area(self):
            return self.r**2*pi
    c1 = Circle(5)
    print(c1.permeter())  #圆的周长
    print(c1.area())      #圆的面积
    

    from math import pi
    class Circle:
        def __init__(self,r):
            self.r = r
        @property
        def permeter(self):
            return 2*pi*self.r
        @property
        def area(self):
            return self.r**2*pi
    c1 = Circle(5)
    print(c1.permeter)  #圆的周长,可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
    print(c1.area)      #圆的面积

    注意:此时的特性area和perimeter不能被赋值。

     1 from math import pi
     2 class Circle:
     3     def __init__(self,r):
     4         self.r = r
     5     @property
     6     def permeter(self):
     7         return 2*pi*self.r
     8     @property
     9     def area(self):
    10         return self.r**2*pi
    11 c1 = Circle(5)
    12 c.area=3    #为特性area赋值
    此时特性area和perimeter不能被赋值

    为什么要用property

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

    面向对象的封装有三种方式:

    • 【public】这种其实就是不封装,是对外公开的
    • 【protected】这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开
    • 【private】这种封装对谁都不公开

    python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现。

    class Foo:
        def __init__(self,val):
            self.__NAME=val #将所有的数据属性都隐藏起来
    
        @property
        def name(self):
            return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)
    
        @name.setter
        def name(self,value):
            if not isinstance(value,str):  #在设定值之前进行类型检查
                raise TypeError('%s must be str' %value)
            self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME
    
        @name.deleter
        def name(self):
            raise TypeError('Can not delete')
    
    f=Foo('egon')
    print(f.name)
    

    f.name=10 #抛出异常'TypeError: 10 must be str'
    del f.name #抛出异常'TypeError: Can not delete'
    

    一个静态属性property本质就是实现了get,set,delete三种方法。

    class Foo:
        @property
        def AAA(self):
            print('get的时候运行我啊')
        @AAA.setter
        def AAA(self,value):
            print('set的时候运行我啊')
    
        @AAA.deleter
        def AAA(self):
            print('delete的时候运行我啊')
    #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
    f1=Foo()
    f1.AAA
    f1.AAA='aaa'
    del f1.AAA
    

    class Foo:
        def get_AAA(self):
            print('get的时候运行我啊')
        def set_AAA(self,value):
            print('set的时候运行我啊')
        def delete_AAA(self):
            print('delete的时候运行我啊')
        AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应
    f1=Foo()
    f1.AAA
    f1.AAA='aaa'
    del f1.AAA
    

    实际超市促销的例子:

    class Goods:
        def __init__(self):
            # 原价
            self.original_price = 100
            # 折扣
            self.discount = 0.8
    
        @property
        def price(self):
            # 实际价格 = 原价 * 折扣
            new_price = self.original_price * self.discount
            return new_price
        
        @price.setter
        def price(self, value):
            self.original_price = value
            
        @price.deleter
        def price(self):
            del self.original_price
    obj = Goods()
    obj.price         # 获取商品价格
    obj.price = 200   # 修改商品原价
    print(obj.price)
    del obj.price     # 删除商品原价
    

    三、classmethod内置函数

      

    class Classmethod_Demo():
        role = 'dog'
    
        @classmethod
        def func(cls):
            print(cls.role)
    
    Classmethod_Demo.func()
    

    四、staticmethod内置函数 

    class Staticmethod_Demo():
        role = 'dog'
    
        @staticmethod
        def func():
            print("当普通方法用")
    
    Staticmethod_Demo.func()
    

    .....

  • 相关阅读:
    android基于adb的性能测试
    mysql-3 数据表的创建、增删改查
    17.3.16---python内建函数
    17.3.15---C语言详解FILE文件操作
    17.3.15---关于GPIO控制流水灯的信息
    17.3.15---关于GPIO学习笔记
    17.3.14--对于时钟的知识,涉及到的总结
    17.3.14对于面向对象的理解
    17.3.13--pycharm2和3的常识问题
    17.3.13--python编码问题
  • 原文地址:https://www.cnblogs.com/yaoyaojcy/p/11345333.html
Copyright © 2020-2023  润新知