python面向对象进阶-07类的封装

什么是类的封装

对外隐藏内部实现细节和属性,并提供简易访问的接口

为什么要封装

两个目的:

1.为了保证 关键数据的安全性
​2.对外部隐藏实现细节,隔离复杂度

【好处】

  1. 将变化隔离;
  2. 便于使用;
  3. 提高复用性;
  4. 提高安全性;

权限

python中的权限分为两种
1.公开 外界可以直接访问和修改
2.私有 外界不能直接访问和修改,在当前类中可以直接修改和访问

封装的两个层次

1.第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装
2.第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问

封装的使用语法

名字 都是私有的,原则上是仅供内部调用的,外部依然可以_名字调用(但本意为不要调用!!!)
__名字 设置为私有属性或方法 实质是在加载类时候,把__替换成了 _类名_
,外部可以_类名__名字调用(但本意为不要调用)
区别: 不同于_名字,这种封装在外部单纯属性或方法名不会会被调用
ps:因为python一般不会强制要求程序必须怎么怎么的,
python要想与其他编程语言一样,严格控制属性的访问权限,只能借助内置方法如__getattr__

客官,菜(code)来了-->类中对象属性的封装


你好

class Person:
    def __init__(self, id_number, name, age):
        self.__id_number = id_number
        self.name = name
        self.age = age

    def show_id(self):
        print(self.__id_number)

p = Person("1111111111111", "jack", 29)

p.__id_number = "222"
print(p.__id_number)

p.show_id()

客官,菜(code)又来了-->类中对象方法的封装

class PC:
    def __init__(self,price,kind,color):
        self.price = price
        self.kind = kind
        self.color = color

    def open(self):
        print("接通电源")
        self.__check_device()
        print("载入内核")
        print("初始化内核")
        self.__start_services()
        print("启动GUI")
        self.__login()


    def __check_device(self):
        print("硬件检测1")
        print("硬件检测2")
        print("硬件检测3")
        print("硬件检测4")

    def __start_services(self):
        print("启动服务1")
        print("启动服务2")
        print("启动服务3")
        print("启动服务4")

    def  __login(self):
        print("login....")
        print("login....")
        print("login....")

pc1 = PC(20000,"香蕉","黄色")
# pc1.open()

pc1.login()

类的封装的自动变形

在python中用双下划线的方式实现隐藏属性(设置成私有的)
类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:

自动变形的特点:

类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。
这种变形其实正是针对内部的变形,在外部是无法通过__x这个名字访问到的。
在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

自动变形的注意点

这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N
变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形
在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

类的封装-私有模块

python并不会真的阻止你访问私有的属性,模块也遵循这种约定,如果模块中的变量名_private_module以单下划线开头,那么from module import *时不能被导入该变量,但是你from module import _private_module依然是可以导入该变量的

ps: 其实很多时候你去调用一个模块的功能时会遇到单下划线开头的(socket._socket,sys.home,sys.clear_type_cache),这些都是私有的,原则上是供内部调用的,作为外部的你,一意孤行也是可以用的,只不过显得稍微傻逼一点点
python要想与其他编程语言一样,严格控制属性的访问权限,只能借助内置方法如__getattr
,详见面向对象高级部分。

访问被隐藏的属性:

​ 提供用于访问和修改的方法

客官,菜(code)来了

"""
这是一个下载器类,需要提供一个缓存大小这样的属性
缓存大小不能超过内存限制

"""
class Downloader:
    def __init__(self,filename,url,buffer_size):
        self.filename = filename
        self.url = url
        self.__buffer_size= buffer_size

    def start_download(self):
        if self.__buffer_size <= 1024*1024:
            print("开始下载....")
            print("当前缓冲器大小",self.__buffer_size)
        else:
            print("内存炸了! ")

    def set_buffer_size(self,size):
        #可以在方法中添加额外的逻辑
        if not type(size) == int:
            print("大哥 缓冲区大小必须是整型")
        else:
            print("缓冲区大小修改成功!")
            self.__buffer_size = size

    def get_buffer_size(self):
        return self.__buffer_size

d = Downloader("葫芦娃","http://www.baicu.com",1024*1024)

# 通过函数取修改内部封装的属性
d.set_buffer_size(1024*512)

# 通过函数访问内部封装的属性
print(d.get_buffer_size())
print(d.filename)

d.start_download()

由此可见 利用好私有属性在类内部中可以被调用的情况 用函数封装好简易的接口,然后外部通过调用它获得对应函数接口里面执行的设计好的对私有属性的操作结果. 这样的方式来实现外部来访问封装的属性!!

posted @ 2019-09-21 10:54  suren_apan  阅读(102)  评论(0编辑  收藏  举报