(python)学习ing||类学习,@property装饰器

class pers():
    def __init__(self,hp):
        self._hp=hp
    
    @property
    def hp(self):
        return self._hp
    @hp.setter
    def hp(self,hp):
        self._hp=gp if hp>=0 else 0

a=pers(10)
print(a.hp)
a.hp-=15
print(a.hp)
# ~ a.hp(-5)#TypeError: 'int' object is not callable
# ~ print(a.hp)
'''
10
0
'''

来自bing AI的回答(手动修改后)

你好,这是必应。@property装饰器是一种用于定义和控制类属性的工具,它可以让你把一个方法变成一个属性,从而实现对属性的访问、设置和删除的自定义操作。

@property装饰器有以下几个优点:**

  • 保护类的封装性,隐藏内部实现细节,防止属性被随意修改或删除。
  • 简化代码,让方法可以像属性一样直接调用,不需要加括号。
  • 提高性能,可以对属性的计算进行缓存,避免重复计算。
  • 增加灵活性,可以根据需要动态地修改属性的行为和逻辑。

@property装饰器的基本用法是:**

  • 在定义类属性的方法上一行,添加@property,这样就把该方法变成了针对某属性的访问方法,可以直接通过该方法名获得该方法的返回值,而无需加括号,看起来就像是直接获取了某个属性的值。若方法名跟某个属性名相同,则看起来就像直接调用了该属性。而若返回值与该属性的值也相同,则就不仅仅是像了,那跟直接调用该属性效果就一样了。如下:
    @property
    def 【方法名】():
        return 【属性值】
    
    为了能让方法内可以返回对象内属性的值,需要在对函数传入要返回的属性所在的对象,这样方法才能获取到属性的值并返回
    @property
    def 【方法名】(self):
        return self.【属性名】
    
    因为有了@property,调用该方法时就可以只使用方法名而不加括号。看起来就像直接调用了某个属性,若方法名跟某个属性名相同,则看起来就像直接调用了该属性。
    在函数内可以对属性的值进行一些判断和操作以防止返回了不合适的值,这样可以保证调用属性的时候调用出来的值是在预期内的。
    class fighter():
        hp=100
        @property
        def hp(self):
            return self.hp if self.hp>=0 else 0
    aaa=fighter()
    print(aaa.hp)
    
    这样就保证了调用hp时返回的是非负数。
    但是,像这样属性名与方法名完全相同的话,【对象名】.【方法名】【对象名】.【属性名】就会混淆,实际上这样会导致无法再直接调用该属性,所有的【对象名】.【方法名】【对象名】.【属性名】都会被认为是对该方法的调用,甚至def hp(self)内的return self.hp if self.hp>=0 else 0中的self.hp也会被认为是对hp方法的调用,这样就会变成递归了,而且还是没有出口的递归。于是上面的代码就会报错:
          [Previous line repeated 996 more times]
    RecursionError: maximum recursion depth exceeded
    
    意思是(来自bing翻译):
    [上一行重复了 996 次]
    RecursionError:超出最大递归深度
    
    所以方法名与该方法要返回的属性的名称不能完全相同,一般再该属性名前面加一个下划线_,因为调用时最好方便简洁,调用时使用的是方法名,所以方法名最好就是要调用的属性最该有的名称,属性名前加一个下划线即可以与方法名区别也可以起到提示作用,提示该属性有专门的访问方法,最好不要直接调用。直接调用该属性则需要使用带下划线的名字,这样让原本不应该进行的直接调用行为变得特殊,可以起到提醒作用。最终例子如下:
    class fighter():
        _hp=100
        @property
        def hp(self):
            return self._hp if self._hp>=0 else 0
    aaa=fighter()
    print(aaa.hp)
    
    输出为100
  • 在定义设置类属性的方法上,使用@对应方法名.setter装饰器,这样就把该方法变成了针对某属性的赋值方法,可以直接通过该方法名与赋值运算符来进行传参,而不必使用括号,看起来就像直接对某个属性进行了赋值。
    class test():
        _hp=100
        @property
        def hp(self):
            return self._hp 
        @hp.setter
        def hp(self,hp):
            self._hp = hp if hp>=0 else 0
    aaa=test()
    print(aaa.hp)#100
    aaa.hp=1
    print(aaa.hp)#1
    
    注意@hp.setterhp这一部分要与@property下面的方法名保持一致,因为setter是与property对应的一套东西这属于语法部分,错了会报错。但下面的方法名可以自己设,不过不能与方法内部的self.【属性名】中的属性名相同,要不然就又变成没有出口的递归了。至于其它的名字则没有问题,只是这个方法的作用是给某个属性赋值,所以还是和对应的@property方法相同最好。
    上面aaa.hp=1实际是调用了def hp(self,hp)方法,并用赋值符号进行传参,将1传给了形参hp,在方法内部进行了赋值操作,将形参的值赋给了相应的属性的值
  • 在定义删除类属性的方法上,使用@属性名.deleter装饰器,这样就把该方法变成了属性的deleter方法,可以通过del语句删除属性的值。
    这个我还没用过,先不管它了

你可以参考以下链接来了解更多关于@property装饰器的详细信息和示例:

希望这些信息对你有帮助。😊

posted @ 2024-01-27 16:09  Kazuma_124  阅读(33)  评论(0)    收藏  举报