美文网首页
Python property属性 - 将方法转化为变量的故事

Python property属性 - 将方法转化为变量的故事

作者: Devops海洋的渔夫 | 来源:发表于2018-12-30 01:39 被阅读49次

仅供学习,转载请注明出处

什么是property属性

一种用起来像是使用的实例属性一样的特殊属性,可以对应于某个方法

# 淡定创建一个胖子老板类
In [24]: class FatBoss(): 
    ...:     def play(self): 
    ...:         print("胖子老板:淡定玩玩斗地主") 
    ...:     # 定义property属性 
    ...:     @property 
    ...:     def sell(self): 
    ...:         print("胖子老板:淡定卖包芙蓉王")    
    ...:                                                                             

# 淡定创建一个实例
In [25]: fb = FatBoss()                                                              

# 淡定调用普通的实例方法
In [26]: fb.play()                                                                   
胖子老板:淡定玩玩斗地主

# 淡定调用一下property属性对应的方法,淡定报错。这是为什么?
In [27]: fb.sell()                                                                   
胖子老板:淡定卖包芙蓉王
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-27-a42050ff6e4f> in <module>
----> 1 fb.sell()

TypeError: 'NoneType' object is not callable

# 原来property的属性对应的方法,不能写() ,就把它当作 selef.name 来使用,只不过它对应的是一个方法。
# 那么就说明property是不能从外部实例传入参数的。
In [28]: fb.sell                                                                     
胖子老板:淡定卖包芙蓉王

In [29]: FatBoss.sell                                                                
Out[29]: <property at 0x7fd84f7d42c8>

property属性的定义和调用要注意一下几点:

  • 定义时,在实例方法的基础上添加 @property 装饰器;并且仅有一个self参数
  • 调用时,无需括号
    • 方法:fb.sell()
    • property属性:fb.sell

实例 - 京东商城分页

对于京东商城中显示电脑主机的列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据 这个分页的功能包括:

  • 根据用户请求的当前页和总数据条数计算出 m 和 n
  • 根据m 和 n 去数据库中请求数据

为什么需要m和n的数字,首先需要知道例如mysql的分页查询的sql:select * from table_name limit m,n

In [34]: class Pager: 
    ...:     def __init__(self,current_page): 
    ...:         # 用户当前请求的页码 
    ...:         self.current_page = current_page 
    ...:         # 每页默认显示10页数据 
    ...:         self.per_items = 10 
    ...:     #定义property属性,进行起始值m的计算 limit m,n 
    ...:     @property 
    ...:     def calculate_m(self): 
    ...:         val = (self.current_page - 1) * self.per_items 
    ...:         return val 
    ...:     #定义property属性,进行结束值n的计算 limit m,n 
    ...:     @property 
    ...:     def calculate_n(self): 
    ...:         val = self.current_page * self.per_items 
    ...:         return val 
    ...:                                                                             

In [35]:                                                                             

In [35]: p = Pager(1) # 传入当前页码就是第一页                                       

In [36]: p.calculate_m                                                               
Out[36]: 0

In [37]: p.calculate_n                                                               
Out[37]: 10

In [38]:  

In [38]: p = Pager(10) # 传入当前页码就是第10页                                      

In [39]: p.calculate_m                                                               
Out[39]: 90

In [40]: p.calculate_n                                                               
Out[40]: 100

In [41]:  

可以从上面的代码中看出,只要加上 @property 作为修饰器,那么就可以将类中的计算方法当作实例变量直接获取。

property属性的有两种方式

  • 装饰器 即:在方法上应用装饰器
  • 类属性 即:在类中定义值为property对象的类属性

装饰器方式

在类的实例方法上应用@property装饰器

Python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。( 如果类继object,那么该类是新式类 )

经典类,具有一种@property装饰器

In [41]: class FatBoss: 
    ...:     @property 
    ...:     def sell(self): 
    ...:         return "胖子老板:淡定卖包芙蓉王"                                    

In [42]: fb = FatBoss()                                                              

In [43]: print(fb.sell)                                                              
胖子老板:淡定卖包芙蓉王

In [44]:   

新式类,具有三种@property装饰器

In [45]: class FatBoss: 
    ...:     """python3中默认继承object类 
    ...:        以python2、3执行此程序的结果不同,因为只有在python3中才有@xxx.setter  @xxx.deleter 
    ...:     """ 
    ...:     @property 
    ...:     def sell(self): 
    ...:         return "胖子老板:淡定卖包芙蓉王" 
    ...:     # 定义一个price价格的property属性 
    ...:     @property 
    ...:     def price(self): 
    ...:         print('@property') 
    ...:     # 定义property属性price的setter方法 
    ...:     @price.setter 
    ...:     def price(self,value): 
    ...:         print('@price.setter') 
    ...:     # 定义property属性price的deleter方法 
    ...:     @price.deleter 
    ...:     def price(self): 
    ...:         print('@price.deleter') 
    ...:                                                                                  

In [46]: fb = FatBoss()                                                                   

In [47]: fb.price                                                                         
@property

In [48]: fb.price = 17                                                                    
@price.setter

In [49]: fb.price                                                                         
@property

In [50]: print(fb.price)                                                                  
@property
None

从上面可以看出,fb.price = 17 则会自动调用 @price.setter 的方法,那么下面来进行详细示例。

property 的 setter 以及 deleter 方法 - 当肥仔白来胖子老板这里买烟,有折扣哦。

有胖子老板的折扣,再也不怕冷了

注意

  • 经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法
  • 新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法
  • 由于新式类中具有三种访问方式,我们可以根据它们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
In [1]: class FatBoss: 
   ...:     def __init__(self): 
   ...:         # 一包芙蓉王的原价 
   ...:         self.original_price = 26 
   ...:         # 如果是胖子白来买则会有折扣 
   ...:         self.discount = 0.8 
   ...:     #设置一个property变量 
   ...:     @property 
   ...:     def price(self): 
   ...:         # 实际价格 = 原价 * 折扣 
   ...:         new_price = self.original_price * self.discount 
   ...:         return new_price 
   ...:     #设置property的setter方法 
   ...:     @price.setter 
   ...:     def price(self,value): 
   ...:         self.original_price = value 
   ...:     #设置property的delete方法 
   ...:     @price.deleter 
   ...:     def price(self): 
   ...:         del self.original_price 
   ...:                                                                                   

In [2]: fb = FatBoss()                                                                    

In [3]: fb.price                                                                          
Out[3]: 20.8

In [4]: fb.price = 17                                                                     

In [5]: fb.price                                                                          
Out[5]: 13.600000000000001

In [6]: del fb.price                                                                      

In [7]: fb.price                                                                          
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-8b8b5efb4572> in <module>
----> 1 fb.price

<ipython-input-1-56837ac7ad5b> in price(self)
      9     def price(self):
     10         # 实际价格 = 原价 * 折扣
---> 11         new_price = self.original_price * self.discount
     12         return new_price
     13     #设置property的setter方法

AttributeError: 'FatBoss' object has no attribute 'original_price'

In [8]:     

类属性方式,创建值为property对象的类属性

当使用类属性的方式创建property属性时,经典类和新式类无区别

In [8]: class FatBoss: 
   ...:     def sell_ciggite(self): 
   ...:         return "芙蓉王" 
   ...:     # 定义property 
   ...:     SELL = property(sell_ciggite) 
   ...:                                                                                   

In [9]: fb = FatBoss()                                                                    

In [10]: print(fb.SELL)      # 可以从结果上来看,就是调用了 @property 一样的。                                                          
芙蓉王

In [11]:  

property方法中有个四个参数

  • 第一个参数是方法名,调用 对象.属性 时自动触发执行方法 ===> fb.price
  • 第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法 ===> fb.price = 17
  • 第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法 ===> del fb.price
  • 第四个参数是字符串,调用 对象.属性.doc ,此参数是该属性的描述信息

那么这里使用 SELL = property() 的方式,将前面示例中的 setter 以及 deleter 实现

In [17]: class FatBoss: 
    ...:     def __init__(self): 
    ...:         self.original_price = 26 
    ...:         self.discount = 0.8 
    ...:     def price(self): 
    ...:         new_price = self.original_price * self.discount 
    ...:         return new_price 
    ...:     def set_price(self,value): 
    ...:         self.original_price = value 
    ...:     def del_price(self): 
    ...:         del self.original_price 
    ...:     # 定义property属性 
    ...:     Price = property(price,set_price,del_price,"这是price的property描述信息") 
    ...:                                                                                  

In [18]: fb = FatBoss()                                                                   

In [19]: fb.Price                                                                         
Out[19]: 20.8

In [20]: fb.Price = 17                                                                    

In [21]: fb.Price                                                                         
Out[21]: 13.600000000000001

In [22]: del fb.Price                                                                     

In [23]: fb.Price                                                                         
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-23-f1fcd9b37f75> in <module>
----> 1 fb.Price

<ipython-input-17-dd23c68d302b> in price(self)
      4         self.discount = 0.8
      5     def price(self):
----> 6         new_price = self.original_price * self.discount
      7         return new_price
      8     def set_price(self,value):

AttributeError: 'FatBoss' object has no attribute 'original_price'

In [24]:   

从上面的代码可以看出,使用Price = property(price,set_price,del_price,"这是price的property描述信息") 一行代码,就可以省略 @property @price.setter @price.deleter 三个修饰器的使用了。

综上所述:

  • 定义property属性共有两种方式,分别是【装饰器】和【类属性】,而【装饰器】方式针对经典类和新式类又有所不同。
  • 通过使用property属性,能够简化调用者在获取数据的流程

那么说了那么多,有什么应用的例子呢?

不给例子,这就是下场

property属性-应用

私有属性添加getter和setter方法

class Money(object):
    def __init__(self):
        self.__money = 0

    def getMoney(self):
        return self.__money

    def setMoney(self, value):
        if isinstance(value, int):
            self.__money = value
        else:
            print("error:不是整型数字")

使用property设置getter和setter方法

class Money(object):
    def __init__(self):
        self.__money = 0

    def getMoney(self):
        return self.__money

    def setMoney(self, value):
        if isinstance(value, int):
            self.__money = value
        else:
            print("error:不是整型数字")

    # 定义一个属性,当对这个money设置值时调用setMoney,当获取值时调用getMoney
    money = property(getMoney, setMoney)  

a = Money()
a.money = 100  # 调用setMoney方法
print(a.money)  # 调用getMoney方法
#100

使用property的修饰器方式取代getter和setter方法

重新实现一个属性的设置和读取方法,可做边界判定

class Money(object):
    def __init__(self):
        self.__money = 0

    # 使用装饰器对money进行装饰,那么会自动添加一个叫money的属性,当调用获取money的值时,调用装饰的方法
    @property
    def money(self):
        return self.__money

    # 使用装饰器对money进行装饰,当对money设置值时,调用装饰的方法
    @money.setter
    def money(self, value):
        if isinstance(value, int):
            self.__money = value
        else:
            print("error:不是整型数字")

a = Money()
a.money = 100
print(a.money)

关注微信公众号,回复【资料】、Python、PHP、JAVA、web,则可获得Python、PHP、JAVA、前端等视频资料。

相关文章

  • Python property属性 - 将方法转化为变量的故事

    仅供学习,转载请注明出处 什么是property属性 一种用起来像是使用的实例属性一样的特殊属性,可以对应于某个方...

  • 属性Property

    property也是一个类,@property成为属性函数,即可以将python定义的方法当做属性访问,可以对属性...

  • iOS 属性

    @property property = ivar(变量) + set方法 + get方法 我们每次在增加一个属性...

  • 36-@property装饰器

    @property装饰器 Python内置的@property装饰器可以把类的方法伪装成属性调用的方式 。 将一个...

  • 属性@property探索

    @property用来定义变量的属性,定义的变量会自动声明变量,自动生成setter方法和getter方法,便于变...

  • 基本语法

    属性 1.声明属性,会自动生成变量,get方法和set方法,如: @property NSString *name...

  • 52个有效方法阅读笔记(二)

    1.属性和实例变量:属性(property)和实例变量其实就是对象保存数据的一种方法.a. 属性会自动生成获取方法...

  • 连续属性离散化实例

    连续属性离散化,就是将数值型变量转化为离散型变量类似于指标转维度的那种感觉 前面说过,连续属性离散化有几种方式: ...

  • 实例变量、property、method

    实例变量是iOS类内的变量,而property是属性,为方便增加set和get的方法。

  • 属性

    什么是属性? 属性=成员变量+set方法+get方法 我们在OC中用@property来声明一个属性,编译器会自动...

网友评论

      本文标题:Python property属性 - 将方法转化为变量的故事

      本文链接:https://www.haomeiwen.com/subject/pjkplqtx.html