封装

一、什么是封装

对外部隐藏内部的属性和细节方法,仅提供简单的访问接口。(注意:封装有隐藏的意思但不是单纯的隐藏)

二、封装的目的

限制外界对内部数据的访问,提高内部数据的安全性和隔离复杂度。

封装属性:提高数据的安全性。将数据属性隐藏起来,类外就无法直接操作属性,需要类内开辟一个接口来让外部使用。因此,可以在接口内控制任意的控制逻辑,从而严格控制使用者对数据的查看或者修改
封装方法:隔离复杂度。一个内部提供支持的方法,不因该让外界直接访问,就可以直接封装起来

三、如何封装

在类内定义的属性或方法方法前加 __ 开头,没有 __结尾

3.1 封装属性

# # 封装属性
class Teacher:
    def __init__(self,name,age,salary):
        self.name = name
        self.age = age
        self.__salary = salary

    # 访问被封装的属性,称之为访问器
    def get_salary(self,pwd):
        # 可以在接口处添加额外的任何逻辑,来限制外部的访问
        if pwd == "123":
            return self.__salary   # 在类的内部,可以访问
        raise Exception("密码错误")
    # 修改被封装的属性,称之为设置器
    def set_salary(self,new_salary):
        self.__salary = new_salary

t = Teacher("wangyong",25,10000)
# print(t.__salary)      # 报错 AttributeError: 'Teacher' object has no attribute '__salary'
t.get_salary("123")    # 10000
t.set_salary(15000)
t.get_salary()    # 15000
t.__hello = 20
print(t.__hello)    # 20

3.2 封装方法

class ATM:

    def __user_auth(self):
        print("请输入账号密码")

    def __input_money(self):
        print("请输入取款金额")

    def __save_record(self):
        print("记录流水....")

    def withdraw(self):
        self.__user_auth()
        self.__input_money()
        self.__save_record()

atm = ATM()
atm.withdraw()
atm.__user_auth()      # 报错 AttributeError: 'ATM' object has no attribute '__user_auth'
atm._ATM__user_auth()    # 请输入账号密码

四、封装的原理

python是通过 变形的方式来实现的封装
如何变形:在名称带有双下划线开头的变量名字前添加_类名 如_Person__id_card
当然通过变形后的名字可以直接访问被隐藏的属性 但通过不应该这么做
变形仅在类的定义阶段发生一次 后续再添加的带有双下划线的任何属性都不会变形 就是普通属性

class Student:

    def __init__(self, name, age, gender, id_card):
        self.name = name
        self.age = age
        self.gender = gender
        self.__id_card = id_card
     # 封装方法
    def __say(self):
        print('hello')

    def show_id_card(self):
        # 可以在这里添加额外的任何逻辑代码 来限制外部的访问

        # 在类的内部 可以访问
        print(self.__id_card)
s = Student('jack',18,'man',32132111)

# print(s.__id_card) # 报错内部封装了无法访问
# print(s._Student__id_card) # 通过变形拿到结果32132111 (被封装的属性名其实变成了'_Student__id_card')
s.show_id_card() # 32132111 通过函数在类内部访问拿到结果

# s.__id_card = 1233
# print(s.__id_card) # 1233 访问的不是原属性,而是在对象中添加了__id_card
print(s.__dict__) # 'name': 'jack', 'age': 18, 'gender': 'man', '_Student__id_card': 32132111, '__id_card': 1233} 

五、property装饰器

5.1 伪装成普通属性

作用:将一个方法伪装成普通属性

为什么用property:将访问私有属性和普通属性的方式变得一致

与property相关的 两个装饰器
property
对象点被装饰的方法触发(一般用于获取封装属性的值)

setter: 用点语法 给属性赋值时触发 (一般用于设置,给对象设置属性)

deleter: 用点语法删除属性时触发 (一般用于删除属性的值)

class Teacher:
    def __init__(self,name,salary):
        self.name = name
        self.__salary = salary

    @property   # getter 用于能访问私有属性的值,也可以访问普通属性
    def salary(self):
        return self.__salary

    @salary.setter  # 用来设置私有属性的值,也可以设置普通属性
    def salary(self,new_salary):
        self.__salary = new_salary

    @salary.deleter   # 用于删除私有属性的值,也可以删除普通属性的值
    def salary(self):
        del self.__salary

t = Teacher("wangyong",12000)
print(t.salary)         # 12000
t.salary = 15000
print(t.salary)         # 15000
del t.salary
print(t.salary)         # 报错,应被已经被删了,报错原因: AttributeError: 'Teacher' object has no attribute '_Teacher__salary'

5.2 实现计算属性

class Person:
    def __init__(self,name,height,weight):
        self.name = name
        self.height = height
        self.weight = weight
        # self.BMI = weight / (height ** 2)

    @property
    def BMI(self):
        return self.weight / (self.height ** 2)

    @BMI.setter
    def BMI(self,new_BMI):
        print("BMI 不支持自定义.....")


p = Person("egon",1.7,80)
print(p.BMI)
p.BMI = 10

 

posted on 2020-05-19 23:54  软饭攻城狮  阅读(116)  评论(0编辑  收藏  举报

导航