开发者

python知识:装饰器@property到底有啥用途

开发者 https://www.devze.com 2023-01-05 09:17 出处:网络 作者: 无水先生
目录一、提要二、关于属性的约定2.1 类绑定属性2.2 对象绑定属性2.3 私有属性 三、应用@property装饰器3.1 将一个属性转成方法3.2 私有化某些属性3.3 关联性修改3.4 删除属性的deleter方法四、property()函数
目录
  • 一、提要
  • 二、关于属性的约定
    • 2.1 类绑定属性
    • 2.2 对象绑定属性
    • 2.3 私有属性 
  • 三、应用@property装饰器
    • 3.1 将一个属性转成方法
    • 3.2 私有化某些属性
    • 3.3 关联性修改
    • 3.4 删除属性的deleter方法
  • 四、property()函数原理
    • 总结

      一、提要

      python的@property是python的一种装饰器,是用来修饰方法的。

      python @property 装饰器使一个方法可以像属性一样被使用。

      除此之外,还有几个使用场景,本文将叙述这些使用技巧。

      二、关于属性的约定

      首先看下属性的分类:

      2.1 类绑定属性

      一般类内属性是指定义成与类同一存储单元的属性,可以类访问。

      而当类实例化成对象后,类变量将做为拷贝加入对象,对象所访问的属性是一份拷贝。

      这份拷贝修改后易变。

      python知识:装饰器@property到底有啥用途

      验证代码

      class Stranger(object):
          name = 'class name'                #类绑定属性
          def __init__(self, gender=None ):
              self.gender = gender           #对象绑定属性
              self.name = 'new name'         #对象中属性,与类属性的同名拷贝
       
      stan = Stranger('male')
      print(1编程客栈,stan.gender)
      stan.gender = 'famel'
      print(2,stan.gender)
      print(3android stan.name)
      print( 4, Stranger.name)

      结果:

      1 male

      2 famel

      3 new name

      4 class name

      2.2 对象绑定属性

      凡用self定义的属性,都是对象绑定属性,

      • 内部调用时都需要加上self.
      • 外部调用时用 instance_name.property_name进行访问
      class Stranger(object):
          def __init__(self, gender=None ):
              self.gender = gender
       
      stan = Stranger('roma')
      print(stan.gender)
       
      stan.gender = 'Paras'
      print(stan.gender)

      结果: 

      roma

      Paras 

      注意:事实上实例化后的对象,也可以定义属性,外部也可以调用。 

      2.3 私有属性 

      python的私有属性没有编译限定,知识以单下划线_开头,标记此属性是私有的,但是外部也可以自由访问(私有的程度不够多)。

      另一种是双下划线__开头的属性,可以转化成类属性访问

      • 单下划线_开头:只是告诉别人这是私有属性,外部依然可以访问更改
      • 双下划线__开头:外部不可通过instancename.propertyname来访问或者更改,实际将其转化为了_classname__propertyname

      三、应用@propphperty装饰器

      python的@property是python的一种装饰器,是用来修饰方法的。pythonpython @property 装饰器使一个方法可以像属性一样被使用,而不需要在调用的时候带上() 接下来我们会了解什么时候需要使用它,并且在什么场景下需要用到它以及如何合理的使用它。

      python类中@property装饰器,相配合的方法有:

      • setter() 
      • get() 
      • set()

      相配合。

      3.1 将一个属性转成方法

      将一个属性转化为一个方法时,我们最好加上一个@property 装饰器来解决这个问题。

      在方法定义上面加一个@property 装饰器,可以在不改变原有调用方式的同时,来将一个属性改为一个方法。

      class Goods():
              def __init__(self,unit_price,weight):
                  self.unit_price = unit_price
                  self.weight = weight
       
              @property
              def price(self):
                  return self.unit_price * self.weight 
       
      lemons = Goods(7,4)
      print(lemons.price)

         28    

       上文中,price是方法,现在将方法转化成属性调用。注意这个技巧,要知道原类定义中无price这个属性,这是一个临时产生的结果。类同于excel表格的“计算项”。

      3.2 私有化某些属性

      对于某些属性,不可直接访问。这里的“直接”就是“无条件”的意思;而条件的访问,就需要装饰器 @property,下例是双装饰器@property和@age.setter配合,对_age进行条件隔离的例子:

      class Stranger(object):
          d开发者_Go学习ef __init__(self, gender=None, age=None, job=None):
              self.gender = gender
              self._age = age # 这里的成员属性_age需要与成员方法age()区分开
              self.jobb = job
       
          # 读取age
          @property # 实现一个age相关的getter方法
          def age(self):
              return self._age
       
          # 设置age
          @age.setter # 实现一个age相关的setter方法
          def age(self, value):
              if isinstance(value, int):
                  self._age = value
              else:
                  raise ValueError("'int' type need")
                  
       
      if __name__ == "__main__":
          # 创建一个“妹子”
          meizi = Stranger()
       
          meizi.ahttp://www.devze.comge = 18  # 使用时注意是.age,不是._age
          print("年龄:{age}".format(age=meizi.age))

      注意事项:

      • 属性名与方法名一定要区分开,不然会进入死循环(self._age,def age())
      • 实例化的对象使用属性时,不是调用属性(meizi._age),而是用的方法名(meizi.age)
      • @property其实就是实现了getter功能; @xxx.setter实现的是setter功能;还有一个 @xxx.deleter实现删除功能
      • 定义方法的时候 @property必须在 @xxx.setter之前,且二者修饰的方法名相同(age())
      • 如果只实现了 @property(而没有实现@xxx.setter),那么该属性为 只读属性

      3.3 关联性修改

      比如,我们输入了first_name、last_name可以得出fullname,下面代码可以实现全名的属性获取。而反过来,对全名进行修改后,如何将连带的first_name、last_name同步进行修改?。

      下文中的 @fullname.setter就是解决此类问题的。

      class Person():
          def __init__(self, first_name, last_name):
              self.first = first_name
              self.last = last_name
       
          @property
          def fullname(self):
              return self.first + ' ' + self.last
       
          @fullname.setter
          def fullname(self, name):
              first_name, last_name = name.split()
              self.first = first_name
              self.last = last_name
       
          def email(self):
              return '{}.{}@email.com'.format(self.first, self.last)
       
       
      person = Person('zhang', 'san')
      print(person.fullname)
      print(person.last)
      print(person.first)
       
      person.fullname = 'li si'
      print(person.fullname)
      print(person.last)
      print(person.first)

      3.4 删除属性的deleter方法

      setter 方法类似,当我们需要删除一个属性时,我们会使用deleter 方法。

      你可以像定义setter 方法一样来定义一个setter 方法,使用相同的方法名,并在方法上添加@{methodname}.deleter 装饰器 。

      class Person():
          def __init__(self, first_name, last_name):
              self.first = first_name
              self.last = last_name
       
          @property
          def fullname(self):
              return self.first + ' ' + self.last
       
          @fullname.setter
          def fullname(self, name):
              first_name, last_name = name.split()
              self.first = first_name
              self.last = last_name
       
          @fullname.deleter
          def fullname(self):
              self.first = None
              self.last = None
       
          def email(self):
              return '{}.{}@email.com'.format(self.first, self.last)
       
       
      person = Person('zhang', 'san')
      print(person.fullname)
      print(person.last)
      print(person.first)
       
      del person.fullname
       
      print(person.last)
      print(person.first)

      四、property()函数原理

      使用该函数可以将方法直接变成属性,与@property类同。

      函数接口:

      property(fget=None, fset=None, fdel=None, doc=None)

      使用property的代码示例:

      class Stranger(object):
          def __init__(self, gender=None, age=None, job=None):
              self.gender = gender
              self._age = age
              self.jobb = job
       
          # 设置_age
          def set_age(self, age):
              if isinstance(age, int):
                  self._age = age
              else:
                  raise ValueError("'int' type need")
       
          # 读取_age
          def get_age(self):
              return self._age
          
          # 使得实例化对象可以利用.age方式来访问
          age = property(get_age, set_age)
       
       
      if __name__ == "__main__":
          # 创建一个“妹子”
          meizi = Stranger()
       
          meizi.age = 18
          print("年龄:{age}".format(age=meizi.age))

      # 输出:

      #年龄:18

      总结

      以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

      0

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      关注公众号