¥面向对象,封装¥

面向对象

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

  • 继承

  • 封装

    • 封装:就是将数据与功能整和到一起

    • 类里面定义数据和方法的时候,都会有一个需求,某些方法和属性是不能被别人看到的

  • 多态

【二】什么是封装

  • 封装就是对具体对象的一种抽象

  • 就是将某部分的功能和代码隐藏起来,在程序内部看不到,只能在程序内部使用

  • 封装最主要的原因就是保护隐私,将不想让用户看到的功能都隐藏起来

  • **封装的意思就像是隐私,你想让他会看到的就让他看到,不想让它看到的就隐藏起来**

【三】封装隐藏属性

【1】在变量名前面加__

  • 例子:先定义一个类,然后在里面写函数,不想让用户看到的就在变量名前加__

class Student():
    #在变量名前加__:初始化对象的时候就会将变量名进行变形,变形成
    #_Student__SCHOOL_NAME:就是变成,_类名__变量名
    __SCHOOL_NAME="清华"
    
    def __init__(self,name):
        self.name = name
        
student = Student(name="dream")
#得到名字
print(student.__dict__)#{'name': 'dream'}
#对参数值进行修改
student.name = "opp"
print(student.name)#opp
#查看名称空间
print(student.__dict__)#{'name': 'opp'}
# print(Student.__SCHOOL_NAME)#找不到报错:类型对象'Student'没有属性'_SCHOOL_NAME'
print(Student._Student__SCHOOL_NAME)#清华
print(Student.__dict__)#在里面能找到这个:'_Student__SCHOOL_NAME': '清华'

【2】函数属性

  • __dict__:查询函数属性,得到的是个字典

  • __init__:魔法方法--》也称为初始化方法,用于初始化对象状态,用的时候随时调用

class Person:
    SCHOOL_NAME = "清华"
​
    def __init__(self, name):
        self.name = name
​
    def __change_name(self):
        self.name = "nb_" + self.name
        print("进来了")
​
​
student = Person(name="tom")
print(student)#<__main__.Person object at 0x0000026C87D5FFD0>
​
print(student.__dict__)#{'name': 'tom'}
​
print(student.__init__)#<bound method Person.__init__ of <__main__.Person object at 0x0000026C87D5FFD0>>
​
print(Person.__dict__)#里面有很多属性就列举了一个:{ 'SCHOOL_NAME': '清华'}
​
print(Person)#<class '__main__.Person'>
​
print(person._Person__change_name())#不带前缀_Person会报错,表示找不到
#进来了
#没有返回值所以同时返回了:None

【3】什么是初始化过程

class Person:  
    def __init__(self, name, age):  
        self.name = name  
        self.age = age  
  
# 创建一个新的Person对象  
person1 = Person("Alice", 30)  
  
# 此时,person1 对象已经有了 name 和 age 属性  
print(person1.name)  # 输出: Alice  
print(person1.age)   # 输出: 30
在这个例子中,当您调用 Person("Alice", 30) 时,Python 创建了一个新的 Person 对象,并调用了 Person 类的 __init__ 方法来设置该对象的 name 和 age 属性。这就是我们通常所说的“变形”或“初始化”过程。

【4】补充

  • 变形只会发生一次

  • 变形只会发生在初始化的时候

class Person:
    __SCHOOL_NAME = "清华"
​
​
student = Person()
# print(student.__SCHOOL_NAME)#会报错
student.__SCHOOL_NAME = '北大'
print(student.__SCHOOL_NAME)#北大
print(Person.__dict__)#{'_Person__SCHOOL_NAME': '清华'}
print(student.__dict__)#{'__SCHOOL_NAME': '北大'}
​
#这两个不是一个东西:print(Person.__dict__)和print(student.__dict__)
#student.__SCHOOL_NAME = '北大':只是加到了student属性里面

【四】什么是开放接口

  • 定义属性,隐藏属是为了不让用户看到对应的功能和逻辑

  • 但是我们要给用户对应的修改接口

class Teacher:
    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
​
​
# 实例化类得到对象
teacher = Teacher("dream", 18)
# 代用对象中的方法,修改对象的信息
# age 必须是数字类型,但是给了字符串,所以一定会报错
teacher.set_info('hope', '22')
#报错信息:r'''
Traceback (most recent call last):
  File "E:\PythonProjects\10面向对象\02封装.py", line 140, in <module>
    teacher.set_info('hope', '22')
  File "E:\PythonProjects\10面向对象\02封装.py", line 131, in set_info
    raise TypeError('年龄必须是整型')
TypeError: 年龄必须是整型
'''
# 调用对象的方法修改对象的信息 , 符合要求就能修改成功
teacher.set_info('Hope', 22)
​
# 查看对象的信息
teacher.tell_info()
# 姓名:Hope,年龄:22

  • 总结

    • 总结隐藏属性与开放接口,本质就是为了明确地区分内外,类内部可以修改封装内的东西而不影响外部调用者的代码;

    • 而类外部只需拿到一个接口,只要接口名、参数不变,则无论设计者如何改变内部实现代码,使用者均无需改变代码。

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

【五】装饰器property拓展

  • property是一种特殊的属性,将函数的返回值作为数据属性返回

class Student:
    def __init__(self, name):
        self.name = name
​
    @property
    def vip_name(self):
        return self.name
​
​
student = Student(name='dream')
print(student.name)
# 不加property之前
# print(student.vip_name)  # <bound method Student.vip_name of <__main__.Student object at 0x000001F2944AB190>>
# print(student.vip_name())  # dream
# 加了property之后
print(student.vip_name)  # dream
print(student.vip_name())  # 加了property之后,后面就不能有(),有就会报错

【1】BIM例子

# 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 BMI:
    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)


dream = BMI(name='dream', weight=64, height=1.7)

print(dream.bmi)

【2】为什么使用property

  • 在编程语言中有三种封装方式

    • public:不封装,是对外公开的

    • protected:对外不公开,对内公开

    • private:对谁用不公开

(1)方法一

  • 在使用property之后

    • 修改 :@函数名.setter,要在修改的函数头上,就像用装饰器那样

    • 删除:@函数名.deleter,要在修改的函数头上,就像用装饰器那样

#例题
class Person(object):
    def __init__(self, name):
        self.__name = name

    # 给当前函数名添加装饰器 property
    # 将当前 函数名作为一个数据属性返回
    @property
    def vip_name(self):
        # 返回值可以是字符串也可以是其他内容
        return self.__name

    # 修改 和 property 包装的函数名一致 并且加 .setter
    # 修改当前变量民的时候会触发
    @vip_name.setter
    def vip_name(self, value):
        print(value)
        self.__name = value
    
    # 删除  和 property 包装的函数名一致 并且加 .deleter
    # 删除当前变量民的时候会触发
    @vip_name.deleter
    def vip_name(self):
        del self.__name


person = Person(name='dream')
# 查看
print(person.vip_name)
# <bound method Person.name of <__main__.Person object at 0x000001EE86C22340>>

# 修改
person.vip_name = 'opp'
print(person.vip_name)

# 删除
# del person.vip_name
# print(person.vip_name)

(2)方法二

  • 使用包装的形式

  • 区别就在于,它在最后,包所有函数名进行了包装

    • vip_name = property(get_vip_name, set_vip_name, del_vip_name)

class Person(object):
    def __init__(self, name):
        self.__name = name

    # 给当前函数名添加装饰器 property
    # 将当前 函数名作为一个数据属性返回
    def get_vip_name(self):
        # 返回值可以是字符串也可以是其他内容
        return self.__name

    # 修改 和 property 包装的函数名一致 并且加 .setter
    # 修改当前变量民的时候会触发
    def set_vip_name(self, value):
        print(value)
        self.__name = value

    # 删除  和 property 包装的函数名一致 并且加 .deleter
    # 删除当前变量民的时候会触发
    def del_vip_name(self):
        del self.__name

    vip_name = property(get_vip_name, set_vip_name, del_vip_name)

person = Person(name='dream')
# 查看
print(person.vip_name)
# <bound method Person.name of <__main__.Person object at 0x000001EE86C22340>>

# 修改
person.vip_name = 'opp'
print(person.vip_name)

# 删除
del person.vip_name
print(person.vip_name)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值