从0.1开始学Python——[20]

本文介绍了Python面向对象编程中的封装概念,包括使用getter和setter方法来保护类的属性,以及如何通过property装饰器简化属性访问。通过示例展示了如何限制用户直接修改属性,以及如何在setter方法中添加验证。最后,讨论了使用双下划线隐藏属性以及property装饰器的使用,使得代码更加安全和易用。
摘要由CSDN通过智能技术生成

上次练习说到我们需要想办法让用户没办法随意修改我们的类的属性等信息,那么下面来学习相关的方法。

封装

封装是面向对象的三大特性之一,它指的是隐藏对象中的一些属性和方法,隐藏后普通用户将无法查看,更无法操作这些数据。隐藏属性最简单的方法是改属性名,让属性名和形参不同名

class Yundingzhiwang():  # 棋王养成用类
    def __init__(self,name,pay,combo,equipment):  # 卡牌的基本信息
        self.fake_name = name
        self.fake_pay = pay
        self.combo = combo
        self.equipment = equipment

nn.pay = '5'
print(nn.fake_pay)
3

但是这种方法对方找到了属性名还是能改,意义不大。因此,提供两个方法,get_属性名(getter方法)set_属性名(setter方法)。这里的属性名不一定是你的真属性名。

getter方法和setter方法

这个两个方法的作用很直观,就是获得对象的属性名对应的属性值和修改对象的属性名对应的属性值,而属性名由你填写,别人不知道。

class Yundingzhiwang():  # 棋王养成用类
    def __init__(self,name,pay,combo,equipment):  # 卡牌的基本信息
        self.real_name = name
        self.real_pay = pay
        self.combo = combo
        self.equipment = equipment
    def work(self):  # 发挥卡牌战力的方法
        print('触发%s羁绊'%self.combo)
    def up(self):  # 提升卡牌战力的方法
        print('花%s钱升到三星'%int(int(self.real_pay)*9))
    def zhuc(self):  # 让卡片成为主c的方法
        print('把%s给合成成装'%self.equipment)
    def get_name(self):
        return self.real_name
    def set_name(self,name):
        self.real_name = name

print(nn.get_name())
nn.set_name('努努和威朗普')
print(nn.get_name())
努努
努努和威朗普

这样就在一定程度上确保了数据安全性。就是说,面向用户时,可以不用显示属性名,只选择性地提供这些方法,这样就可以让用户可读可写,可读不可写(去掉setter方法),或者不可写不可读(全去掉)。
另外用setter方法还可以确保输入内容合法性,只要在方法里面加入判断语句就行了。

class Yundingzhiwang():  # 棋王养成用类
    def __init__(self,name,pay,combo,equipment):  # 卡牌的基本信息
        self.real_name = name
        self.real_pay = pay
        self.combo = combo
        self.equipment = equipment
    def work(self):  # 发挥卡牌战力的方法
        print('触发%s羁绊'%self.combo)
    def up(self):  # 提升卡牌战力的方法
        print('花%s钱升到三星'%int(int(self.real_pay)*9))
    def zhuc(self):  # 让卡片成为主c的方法
        print('把%s给合成成装'%self.equipment)
    def get_name(self):
        return self.real_name
    def set_name(self,name):
        self.real_name = name
    def get_pay(self):
        return self.real_pay
    def set_pay(self,pay):
        if pay > 0:
            self.real_pay = pay

nn.set_pay(-1)
print(nn.get_pay())
3

这两个方法还有一些好处,当你定义一些通过初始化属性进行计算的新属性的方法时,就不需要再键入新的属性名了,只需要在计算该属性的方法里面返回计算表达式即可,而且初始化属性的值发生改变的时候,结果自然随之改变,不需要手动修改。

class Star_platinum():  # 白金之星的能力
    def __init__(self,power,speed):  # 力量和速度定为主要属性
        self.real_power = power
        self.real_speed = speed
    def get_power(self):
        return self.real_power
    def set_power(self,power):
        self.real_power = power
    def get_speeed(self):
        return self.real_speed
    def set_speed(self,speed):
        self.real_speed = speed
    def get_punchdamage(self):
        return self.real_power * self.real_speed

jtl = Star_platinum(100,100)
print(jtl.get_punchdamage())
jtl.set_power(10)
jtl.set_speed(10)
print(jtl.get_punchdamage())
10000
100

强硬一些的隐藏

上面所谓的隐藏,说白了还是改属性名,并且限定特定方法让用户能或不能访问和修改,但是这对知道真正属性名的人没有作用,因为那些人还是可以用self.属性名=×××的方式进行修改。
因此我们需要隐藏一些属性,并且能一定程度上确保外部用户不能对这些东西动手动脚。这个方法就是,在属性名的开头打上双下划线

class Star_platinum():  # 白金之星的能力
    def __init__(self,power,speed):  # 力量和速度定为主要属性
        self.real_power = power
        self.real_speed = speed

jtl = Star_platinum(100,100)
print(jtl.real_speed)
100

可以看到知道真的属性名是可以访问的。

class Star_platinum():  # 白金之星的能力
    def __init__(self,power,speed):  # 力量和速度定为主要属性
        self.real_power = power
        self.__speed = speed
    def get_power(self):
        return self.real_power
    def set_power(self,power):
        self.real_power = power
    def get_speeed(self):
        return self.__speed
    def set_speed(self,speed):
        self.__speed = speed
    def get_punchdamage(self):
        return self.real_power * self.__speed

jtl = Star_platinum(100,100)
print(jtl.__speed)
Traceback (most recent call last):
  File "D:/4classcode/4classcode/lianxi.py", line 706, in <module>
    print(jtl.__speed)
AttributeError: 'Star_platinum' object has no attribute '__speed'

可以看到,真正的无法查看出现了,直接报错。

jtl.__speed = 200
print(jtl.get_speeed())
100

可以看到,修改也是无济于事。
但是,这种方法的本质是Python自动把带有双下划线开头的属性名改成了其他名字,具体来说,是改成了 (下划线)类名(双下划线)属性名 ,按照上面的例子即是(下划线)Star_(注意这个下划线是类里面的)platinum(双下划线)speed。

jtl._Star_platinum__speed = 200
print(jtl.get_speeed())
200

可以看到,知道真正的属性名之后还是可以改。但是这种方法显然更加强硬,对于不知道真正属性名的用户这种隐藏更厉害。但是也并不能完全达到想要的效果。
单下划线开头的属性名,可以访问,但是这样表示私有属性,可以有一定的提示作用,它没有程序上的强制效果,但是对外部用户这种符号可以起到提醒作用,是一个共识性的符号。而且在Python中,这样命名会让用户在打出一个下划线的时候不自动显示出这些单下划线的属性名。
在这里插入图片描述
可以看出不会自动显示_name这一项。

property装饰器

方法的名字一般有一些提示的作用,例如我们叫获取name属性的方法叫.get_name(),但是如果方法的名字太长了,那用起来说实话比较麻烦,所以我们需求一种方法,可以用属性名或者简写属性名来代替方法名,而且调用方法的时候直接.属性名,不需要括号,这样就使我们又可以调用方法,又可以像查看属性一样方便。

class Lpl():
    def __init__(self,name):
        self._name = name
    @property
    def name(self):
        print('方法在执行')
        return self._name

lqs = Lpl('撕少')
print(lqs.name)
方法在执行
撕少

结果表明,我们不再顾及方法命名,而使用装饰器,这样既精简了指令,而且还正常运行了方法。而且这种命名可以和上面隐藏属性的方法一起使用,就按上面的例子讲,我不设置setter方法,把真正的属性名改成自定义属性名_name,但是把getter方法改成和调用name属性一样的形式,这样就有用户修改属性指令无法运行,但是却能查看属性名对应属性的效果。

lqs.name = 'lqs'
Traceback (most recent call last):
  File "D:/4classcode/4classcode/lianxi.py", line 721, in <module>
    lqs.name = 'lqs'
NameError: name 'lqs' is not defined

可以看到报错。
不过要注意,用property装饰器装饰方法,只能装饰getter方法,而且最好把方法名改成和真正属性名对应形参一样的名字。

装饰setter的装饰器

这个装饰器不太一样,用法是@属性名对应形参的名字.setter。原因很简单,这就是为什么getter的装饰器中建议最好把方法名改成和真正属性名对应形参一样的名字。因为如果改成别的名字,那下面这个装饰器的名也得跟着改,也就是说要保证setter和getter的方法名一样

class Lpl():
    def __init__(self,name):
        self._name = name
    @property
    def name(self):
        print('方法在执行')
        return self._name

    @name.setter
    def name(self,name):
        print('setter在执行')
        self._name = name

lqs = Lpl('撕少')
print(lqs.name)
lqs.name = 'lqs'
print(lqs.name)
方法在执行
撕少
setter在执行
方法在执行
lqs

这就达到效果了,看着都是lqs.name,但是根据指令不同,调用的是不同方法。
注意,getter是必须的,上面也写了,没有可写不可读这个选项,因为没有getter方法,setter方法是会报错的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值