(7)类的封装--反射方法

1. 什么是封装
装:将属性装到一个容器里,该容器可以是类也可以是对象

封:指的是将装到容器里的对象给隐藏起来,该隐藏是对外不对内的

2. 为何要封装

隐藏数据属性的目的

把数据属性隐藏起来,是为了外使用者不能直接操作属性,而是通过类内部开辟的接口来间接地操作属性 我们可以在接口之上附加任意的控制逻辑,从而严格控制使用者对属性的操作

隐藏函数属性的目的:

 

3. 如何封装
在函数名或属性前加 __或者_

PS:反射取__的函数或者属性时必须在传入的字符串名前面加‘_类名’,否则取不到函数,包括hasattr判断也同理

PS:如果是_的函数则可以直接用反射系列的方法取值

例:

 

class FTPHandler():
def handle(self):
print('1')
if hasattr(self,"_FTPHandler__get"): # hasattr判断如果有这个函数名,调用私有地址的方式是_父类名+私有地址的函数名将名字拼成私有地址的格式
print('yes')
else:
print('输入错误')

def __get(self):
'''收取文件的函数'''
print('123')

ftp = FTPHandler()
ftp.handle()

 

封装实例

class Foo:
__x=1 #这里就是封装
def __init__(self,name,age):
self.__name=name #这里是封装
self.__age=age #这里是封装

def tell_info(self): #这里定义一个函数用来查看类体内的封装
print(self.__name,self.__age,self.__x,Foo.__x)

print(Foo.__x) #这时候已经访问不到x这个值,外部访问已经查找不到
obj=Foo('egon',18)
print(obj.__name,obj.__age) #这里对象也访问不到,外部访问已经查找不到
print(obj.__dict__)
PS:原理就是类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里的,生成一个key:value的字典,然后在代码执行时候就会以key查找
但凡__开头的属性,在类定义的时候,就会在字典里加上__开头存入
obj.tell_info() #类内的函数可以访问到
# print(Foo._Foo__x)#通过这样的方式就可以访问到,所以不是绝对隐藏
# print(obj._Foo__name)

注意:
1. __开头属性会在类定义阶段检测语法时发生变形,变形规则: _类名__属性名
2. 类定义阶段之后新增的__开头的属性不会变形
3. 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为隐藏的

class Foo:
__x = 1 #这里在定义的时候就发生了变形

def __init__(self, name, age):
self.__name = name #这里在定义的时候就发生了变形
self.__age = age #这里在定义的时候就发生了变形

def tell_info(self):
print(self.__name) #这里在定义的时候就发生了变形

obj=Foo('egon',18)

obj.__yyy=111 #类定义之后新增不会发生变形
print(obj.__dict__) #查看下有没有变形
print(obj.__yyy) #这里可以直接访问到



class Foo:
def __f1(self): #在类定义阶段变形成Foo__f1
print('Foo.f1')

def f2(self):
print('Foo.f2')#在类定义阶段变形成Foo__f2
self.__f1() #这里调用自己,不会和Bar里面的f1冲突

class Bar(Foo):
def __f1(self): #在定义阶段变形成Bar__f1
print('Bar.f1')

obj=Bar()
obj.f2()

PS:想访问的方法就是访问自己,把方法变成赢藏的,然后在一个地方调用,一定不会和别的同名的冲突,为什么不会冲突,因为在类定义阶段大家都统一进行了变形,变形规则就是自己的类名,所以和别人冲突不了,类名是不会重复的

 

为什么要封装

1、封装数据属性

意图:将数据隐藏起来,从而类的使用者无法直接操作该数据属性,需要类的设计者在类的内部开辟接口,让类的使用者用过接口来间接的操作数据,类的设计者可以在接口之上附加任意逻辑,从而严格控制类的使用者对属性的操作

隐藏数据属性的目的:
class People:
def __init__(self,name,age):
self.__name=name
self.__age=age

def tell_info(self): #类内部开了一个接口让外部访问,还可以定制访问格式
print('<Name:%s Age:%s>' %(self.__name,self.__age))

def set_info(self,name,age): #类内部开了一个修改接口,可以限定外部传入的格式
if type(name) is not str:
print('名字必须是str类型傻叉')
return
if type(age) is not int:
print('年龄必须是int类型傻叉')
return
self.__name=name #这里就可以限定用户修改的格式,而不能直接修改
self.__age=age

def del_info(self): #删除用户名和密码也是,只能从类内部删除,将删除代码放入一个函数,存在类的内部,需要删除时候调用这个函数
del self.__name
del self.__age

obj=People('egon',18)
obj.tell_info() #这里通过接口访问到数据

obj.set_info('EGON',19)
obj.tell_info()#这里通过接口修改了数据

obj.del_info()
print(obj.__dict__)

PS:封装数据可以在接口之上附加任意设计者想要的逻辑,比如严格控制用户对属性的增删该查操作,比如修改用户名字的格式等

 

 2、封装函数

意图:比如取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做隔离了复杂度,同时也提升了安全性

class ATM:
    def __card(self):
        print('插卡')
    def __auth(self):
        print('用户认证')
    def __input(self):
        print('输入取款金额')
    def __print_bill(self):
        print('打印账单')
    def __take_money(self):
        print('取款')

    def withdraw(self):#做了封装后,直接在类的内部开辟了一个整合功能的函数,外部调用的时候直接调用这个函数即可,并不用考虑有多少功能,也看不到有多少功能
        self.__card()
        self.__auth()
        self.__input()
        self.__print_bill()
        self.__take_money()

a=ATM()
a.withdraw()

posted @ 2018-12-09 21:24  clyde_S  阅读(258)  评论(0编辑  收藏  举报