首页 > 编程语言 >Python进阶之封装

Python进阶之封装

时间:2024-05-10 16:23:47浏览次数:21  
标签:__ .__ 封装 进阶 student Python self Student name

【一】面向对象的三大特性

  • 面向对象的三大特性:封装、继承、多态
  • 其中最重要的就是封装,封装就是将数据和功能整合到一起
  • 我们可以对封装在类和对象中的属性进行访问的控制,有隐藏的和开发的接口

【1】什么是封装

  • 封装是对具体对象的一种抽象
  • 封装就是将某些数据和功能隐藏起来,只能通过程序内部查看,而外部看不了

【2】为什么要封装

  • 封装就是为了保护隐私,不让别人知道内部的功能

【3】封装的方法

  • 你的身体的每一个器官,每一块皮肤,以至于你这整个人,都是属于自己一个人的,也只有你一个人可以使用,别人也用不了,也看不到你怎么用的

【二】隐藏属性

【1】隐藏属性方法

  • 采用双下划线开头的方式将属性隐藏起来
  • 类中所有双下滑线开头的属性都会在类定义阶段、检测语法时自动变成_类名__属性名的形式
class Student:
    __SCHOOL = "北京大学"

    # 定义函数时,会检测函数语法,所以__开头的属性也会变形
    def __init__(self, name):
        self.__name = name
        
    # 定义函数时,会检测函数语法,所以__开头的属性也会变形
    def __read(self):
        print(f"学生{self.__name}的学校是{self.__SCHOOL}")


student = Student('ligo')
print(student.name)
# AttributeError: 'Student' object has no attribute 'name'

【2】隐藏属性访问

  • 可以通过__类名__变量名来从类外部访问属性
class Student:
    __SCHOOL = "北京大学"

    # 定义函数时,会检测函数语法,所以__开头的属性也会变形
    def __init__(self, name):
        self.__name = name

    # 定义函数时,会检测函数语法,所以__开头的属性也会变形
    def __read(self):
        print(f"学生{self.__name}的学校是{self.__SCHOOL}")


# 查看当前类的名称空间
print(Student.__dict__)
# '_Student__SCHOOL': '北京大学'
# 发现可以通过特定的方法,仍然可以访问到相应的属性 _Student__SCHOOL
print(Student.__SCHOOL) #找不到
print(Student._Student__SCHOOL)  # 北京大学(可以找到)

student = Student('ligo')
# 查看对象的名称空间
print(student.__dict__)
# {'_Student__name': 'ligo'}
# 也可以访问到类里的函数_Student__read
student._Student__read()
# 学生ligo的学校是北京大学

【3】隐藏方法变形

  • 在类内部是可以直接访问双下滑线开头的属性的
class Student:
    __SCHOOL = "北京大学"

    # 定义函数时,会检测函数语法,所以__开头的属性也会变形
    def __init__(self, name):
        self.__name = name

    # 定义函数时,会检测函数语法,所以__开头的属性也会变形
    def __read(self):
        print(f"学生{self.__name}的学校是{self.__SCHOOL}")
        
    # 直接在内部调用
    def read(self):
        self.__read()
        print(self.__name)


student = Student('ligo')
student.read()
# 学生ligo的学校是北京大学
# ligo

【4】变形操作只会发生一次

  • 变形操作只在类定义阶段发生一次,在类定义之后的赋值操作,不会变形
class Student:
   __SCHOOL = "北京大学"

   # 定义函数时,会检测函数语法,所以__开头的属性也会变形
   def __init__(self, name):
       self.__name = name

   # 定义函数时,会检测函数语法,所以__开头的属性也会变形
   def __read(self):
       print(f"学生{self.__name}的学校是{self.__SCHOOL}")


# 修改类的变量
Student.__SCHOOL = '清华大学'
# 查看当前类的名称空间
print(Student.__dict__)
# '_Student__SCHOOL': '北京大学'
# 将__SCHOOL改为_Student__SCHOOL
Student._Student__SCHOOL = '清华大学'
print(Student.__dict__)

student = Student('ligo')
# 修改对象变量
student.__name = 'scott'
# 查看对象的名称空间
print(student.__dict__)
# {'_Student__name': 'ligo', '__name': 'scott'}
# 可以直接根据键取值
print(student.__name)  # scott
student._Student__read()
# 学生ligo的学校是清华大学

【三】开放接口

  • 定义属性就是为了使用,所以隐藏并不是目的

【1】隐藏数据属性

  • 将数据隐藏起来就限制了类外部对数据的直接操作,然后类内应该提供相应的接口来允许类外部间接地操作数据,接口之上可以附加额外的逻辑来对数据的操作进行严格地控制
class Student(object):
    def __init__(self, name, school):
        self.__name = name
        self.__school = school

    # 对外提供访问学生信息的接口
    def read(self):
        print(f"学生{self.__name}的学校是{self.__school}")

    # 对外提供设置学生信息的接口,并附加类型检查的逻辑
    def set_info(self, name, school):
        if not isinstance(name, str):
            raise TypeError('学生姓名必须是字符串类型的')
        if len(school) != 4:
            raise TypeError('必须是四字大学')
        self.__name = name
        self.__school = school


# 实例化类得到对象
student = Student(name='ligo', school='北京大学')
student.read()  # 学生ligo的学校是北京大学
# 修改
student.set_info(name='ligo', school='清华大学')
student.read()  # 学生ligo的学校是清华大学

# 不符合要求会抛出异常
student.set_info(name='ligo', school='大学')
student.read()  # TypeError: 必须是四字大学

【2】隐藏函数属性

  • 目的的是为了隔离复杂度
  • 例如ATM有插卡、身份认证、输入金额、打印小票、取钱等功能,对于使用者只需要开放取款功能的接口就行了,其余功能我们都可以隐藏起来
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()


obj = ATM()
obj.withdraw()
# 插卡
# 用户认证
# 输入取款金额
# 打印账单
# 取款

【3】小结

  • 隐藏属性与开放接口,是为了明确地区分内外,类内部可以修改封装内的东西而不影响外部调用者的代码
  • 而外部使用者只需拿到一个接口,只要接口名、参数不变,使用者的代码永远无需改变
  • 只要接口这个基础不变,代码的无论怎么修改都没有影响

【四】property

【1】什么是property

  • property是一种特殊的属性,执行函数得到返回值,然后作为数据属性返回
class Student(object):
    school = "清华大学"

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

    @property
    def read(self):
        return f"学生{self.name}的学校是{self.school}"


student = Student(name='ligo')
print(student.name)  # ligo
print(student.read)  # 学生ligo的学校是清华大学

【2】BMI例子

  • BMI指数是用来衡量一个人的体重与身高对健康影响的一个指标
  • 成人的BMI数值:
    • 过轻:低于18.5
    • 正常:18.5-23.9
    • 过重:24-27
    • 肥胖:28-32
    • 非常肥胖: 高于32
  • 计算公式
    • 体质指数(BMI)=体重(kg)÷ 身高^2(m)
    • EX:70kg ÷(1.75×1.75)= 22.86
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)


people = People('ligo', 80, 1.80)

# 触发方法bmi的执行,将people自动传给self,执行后返回值作为本次引用的结果
# 正常我们调用对象的方法应该是people.bmi(),但是这里我们没有加()就能正常调用
print(people.bmi)  # 24.691358024691358

【3】为什么要用property

  • 面向对象的封装有三种方式:
    • public:不封装,是对外公开的
    • protected:对外不公开,但对朋友或者子类公开,就是对内公开
    • private:对谁都不公开
  • public
class Student(object):
    def __init__(self, name):
        self.name = name


student = Student(name='ligo')
# 查看姓名
print(student.name)  # ligo
# 修改姓名
student.name = 'scott'
print(student.name)  # scott
# 删除姓名
del student.name
print(student.name)
# AttributeError: 'Student' object has no attribute 'name'
  • protected
class Student(object):
    def __init__(self, name):
        self.__name = name
        
    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self,value):
        # 通过类型检查后,将值value存放到真实的位置self.__name
        self.__name = value

    @name.deleter
    def name(self):
        del self.__name


student = Student(name='ligo')
# 查看姓名
print(student.name)  # ligo
# 修改姓名
student.name = 'scott'
print(student.name)  # scott
# 删除姓名
del student.name
print(student.name)
# AttributeError: 'Student' object has no attribute 'name'
  • private
class Student(object):
    def __init__(self, name):
        self.__name = name

    def name(self):
        return self.__name

    def show_name(self, value):
        # 通过类型检查后,将值value存放到真实的位置self.__name
        self.__name = value

    def del_name(self):
        del self.__name
        
    # 不使用装饰器,而是使用 包装的 形式
    name = property(name, show_name, del_name)


student = Student(name='ligo')
# 查看姓名
print(student.name)  # ligo
# 修改姓名
student.name = 'scott'
print(student.name)  # scott
# 删除姓名
del student.name
print(student.name)
# AttributeError: 'Student' object has no attribute 'name'

标签:__,.__,封装,进阶,student,Python,self,Student,name
From: https://www.cnblogs.com/ligo6/p/18183502

相关文章

  • Python-有序字典OrderedDict练习题
    问题:读取键盘输入结果,创建n个键值对,将其排序后放入有序字典并输出。详细描述:根据提示,实现函数功能:读取n(n>0)行输入,以每一行的数据为key,行号(从0开始)为value,建立n对键值对,然后将他们按照key排序后,放入一个有序字典,最后输出这个有序字典。importcollectionsdefFunc():pairs......
  • python教程10-集合
    集合(set)是一个无序的不重复元素序列。集合中的元素不会重复,并且可以进行交集、并集、差集等常见的集合操作。可以使用大括号 {} 创建集合,元素之间用逗号 , 分隔,或者也可以使用 set() 函数创建集合。集合创建:注意:创建一个空集合必须用 set() 而不是 {},因为 {} ......
  • python教程10-元祖
    元组(tuple)与列表类似,不同之处在于元组的元素不能修改。因此很少使用元组使用小括号 (),列表使用方括号 [] 元组中只包含一个元素时,需要在元素后面添加逗号 , ,否则括号会被当作运算符使用:元祖调用:修改元祖元组中的元素值是不允许修改的,但我们可以对元组进行连接组......
  • node.js 封装操作文件类
    constfs=require('fs');constpath=require('path');classFile{constructor(fileName,name,ext,isFile,size,createTime,updateTime){this.fileName=fileName;this.name=name;this.ext=ext;......
  • python异常的一些代码笔记
    点击查看代码whileTrue:try:x=int(input("请输入一个数字:"))print("你输入的数字是:",x)except:print("异常,输入的不是数字:")try:a=input("请输入被除数:")b=input("请输入除数:")c=float(a)/float......
  • 使用Python进行数据分析的基本步骤和技巧
    ......
  • python教程9-第三方模块安装
    https://pypi.python.org/pypi是python的开源模块库。收录了⾃全世界python开发者贡献的模块,⼏乎涵盖了你想⽤python做的任何事情。事实上每个python开发者,只要注册⼀个账号就可以往这个平台上传你⾃⼰的模块,这样全世界的开发者都可以容易的下载并使⽤你的模块。下载和安装:......
  • python 映射类型 dict
    dict定义字典(Dict)是一种用于存储键-值对数据的数据结构。字典使用花括号{}来创建,每个键值对之间使用冒号:分隔。可变的、无序的、key不重复。dict的特点键值对存储:字典是由键值对构成的集合,每个键值对之间使用冒号(:)分隔,键和值之间使用逗号分隔,所有键都是唯一的。无序性:字典......
  • python教程8-页面爬虫
    python爬虫常用requests和beautifulSoup这2个第三方模块。需要先进行手动安装。requests负责下载页面数据,beautifulSoup负责解析页面标签。关于beautifulSoup的api使用,详见api页面:https://beautifulsoup.readthedocs.io/zh-cn/v4.4.0/#find-all豆瓣评论中邮箱数据爬取案例:imp......
  • 微信电脑文件清理python程序
    importos,refromitertoolsimportcombinations#两两组合defcombinations_iterative(elements):returnlist(combinations(elements,2))#将按照字符串长度升序排列defsort_by_length(lst):#定义一个自定义排序函数,按字符串长度排序deflength_sort(it......