面向对象——封装

封装

将具体、复杂的细节封装在一起。

1. 如何将属性隐藏

如果想让属性或方法隐藏,在其前加 ‘__’ 双下划线,python就将其视为私有。
注意:
(1). 私有变量是在定义时生成的。
(2). python没有实现绝对的私有,而是在定义时将私有属性解析 ‘_类名__属性’,(单下划线类名双下划线属性)

#其实这仅仅这是一种变形操作
#类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:

class A:
    __x = 1  #定义时被解释为 _A__x

    def __init__(self, name):
        self.__name = name # 定义时被解释为 self._A__name

    def __foo(self): #定义时被解释为 _A__foo
        print('run foo')
    def bar(self):
        self.__foo() #只有在类内部才可以通过__foo的形式访问到.
        
# 外部无法通过‘类名.属性’的方式访问
# print(A.__x) AttributeError: type object 'A' has no attribute '__x'

a = A('yk')
print(a.__dict__)  # {'_A__name': 'yk'}
print(_A__name)  # yk 可以通过_类名__x的形式访问

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

问题:
1、这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N。
2、变形的过程只在类的定义是发生一次,在定义后的赋值操作,不会变形

3、在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

#正常情况
class A:
    def fa(self):
        print('from A')
    def test(self):
        self.fa()

class B(A):
    def fa(self):
        print('from B')
        
 b=B()
 b.test() # from B


#把fa定义成私有的,即__fa
class A:
    def __fa(self): #在定义时就变形为_A__fa
        print('from A')
    def test(self):
        self.__fa() #只会与自己所在的类为准,即调用self._A__fa

class B(A):
    def __fa(self):
        print('from B')

b=B()
b.test() # from A

2. 封装不是单纯意义的隐藏

# 1:封装数据。将数据隐藏起来这不是目的。
# 隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,
# 以此完成对数据属性操作的严格控制。

class People:
    def __init__(self,name,age):
        self.__name = name
        self.__age = age
        
    # 访问接口
    def tell_info(self):
        print('姓名:%s,年龄:%s' % (self.__name, self.__age))
        
    # 修改接口
    def set_info(self, name, age):
        # 添加自己的控制逻辑
        if not isinstance(name, str):
            raise TypeError('姓名必须是字符串类型')
        if not isinstance(age, int):
            raise TypeError('年龄必须是整型')
        self.__name = name
        self.__age = age
        
p = People('yk',18)
p.tell_info() # yk,年龄:18
p.set_info('小明',15)
p.tell_info() # 小明,年龄:15
p.set_info('小花','14') # 报错 TypeError: 年龄必须是整型
# 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()

猜你喜欢

转载自www.cnblogs.com/ykgo/p/9356338.html