面向对象-封装

一、封装如何隐藏属性

class A:
    __x=1

    def __init__(self,name):
        self.__name=name # self._A__name=name

    def __foo(self): # def _A__foo(self):
        print('run foo')


# print(A.__x) # 没有这个值了

a = A('egon')
print(a.__dict__)  # {'_A__name': 'egon'}
这种变形特点:
1、外部无法直接访问到 obj.__AttrName
2、在类内部 obj.__AttrName
3、子类无法覆盖父类 __开头的属性(根本不是一个名字)
class Foo:
    def __func(self): # _Foo__func(self)
        print('from foo')

class Bar(Foo): # _Bar__func(self):
    def __func(self):
        print('from bar')
总结:
1、隐藏只在函数定义的时候才会发生
2、加上__ 后 只能在自己或者自己类里找
class B:
    __x=1

    def __init__(self,name):
        self.__name=name

print(B._B__x)
B.__y=2
print(B.__dict__)

#1.常态
class A:
    def foo(self):
        print('A.foo')

    def bar(self):
        print('A.bar')
        self.foo()

class B(A):
    def foo(self):
        print('B.foo')

b=B()
b.bar()  # A.bar  B.foo

#2.隐藏用法:只调取自己类的,不调取其他类的
class A:
    def __foo(self): # _A__foo
        print('A.foo')

    def bar(self):
        print('A.bar')
        self.__foo() # self._A__foo()

class B(A):
    def __foo(self): #_B__foo
        print('B.foo')

b=B()
b.bar()  # A.bar  A.foo

二、封装的意义

封装数据属性:明确区分内外,控制外部对隐藏的属性的应用
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 not isinstance(name,str):
            print('名字必须是字符串')
            return
        if not isinstance(age,int):
            print('年龄必须是数字类型')
            return
        self.__name=name
        self.__age=age

p=People('egon',18)

# p.tell_info()

# p.set_info('EGON',18)  # 修改为这两个值
# p.tell_info()  # 间接调取

p.set_info(123,18)
p.tell_info()
封装数据属性:隔离复杂度
取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
隔离了复杂度,同时也提升了安全性
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()

特性(property) 

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('egon',52,1.67)
print(p1.bmi)

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

@property 封装逻辑,像是在调取一个普通属性,隐藏了内部逻辑,外观看着像是调取普通的属性。

封装与拓展性

封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;

而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。

这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。

#类的设计者
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏了内部的实现细节,此时我们想求的是面积
        return self.__width * self.__length


#使用者
>>> r1=Room('卧室','egon',20,20,20)
>>> r1.tell_area() #使用者调用接口tell_area
400


#类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了
        return self.__width * self.__length * self.__high


#对于仍然在使用tell_area接口的人来说,根本无需改动自己的代码,就可以用上新功能
>>> r1.tell_area()
8000

 

posted on 2018-12-31 10:01  赫晓蕊  阅读(86)  评论(0编辑  收藏  举报

导航