python中的property及属性与特性之间的优先权
作者:little亮_ 发布时间:2023-02-03 02:36:12
前言
这几天看《流畅的python》这本书了,在一个示例中又看到了property作为装饰器在使用,因为很久没有用这个东西了,对它的一些特性和使用方法等都不是很熟悉,所以又专门在搜了几篇博客和在官方文档中学习了它的相关用法。再者又刚好学到了python中的属性(attribute),所以刚好这两者可以两相对比,也许更好理解!
属性(attribute)
属性的定义
在python中,属性其实是(对象的)属性和(对象的)方法的集合。
一开始我以为就是:属性就是属性,方法就是方法,一个是“属性”,一个是行为,但是在打开IDE写了一个测试案例后,我就信服了:
# python中数据的属性和处理数据的方法统称为属性
class Cat:
def __init__(self, name):
self.name = name
def run(self):
print('小碎步...')
if __name__ == '__main__':
tom = Cat('Tom')
print(tom.__getattribute__('name')) # 对象的属性
print(tom.__getattribute__('run')) # 对象的方法
在这里我定义了一个类,同时在初始化方法中为它添加了一个属性name,然后定义了一个run方法,之后在main方法里创建了tom这个实例,使用__getattribute__()方法来获取它的name属性和run属性,果不其然,居然真的都获取到了!
所以,以后再也不要说属性只是单纯的“属性”了!
属性的用法
属性用法很简单,不管是对象的属性还是方法,都是用.来获取或者调用。
1.设置或修改对象的属性
tom.name='Tom' #设置(修改)对象tom的name属性值为Tom
2.删除对象的属性
del tom.name #使用del关键字删除对象的属性
可以看到,属性删除后就不能再获取了。
3.调用对象的方法(属性)
tom.run() #直接用.调用即可
4.对象的方法置None
对象的方法我们无法删除,但是我们可以将其置为None。
tom.run=None
特性(property)
特性的定义
个人理解:特性就是属性的特例,因为预先知道某些属性的一些特定条件,比如取值范围,类型等等,所以在对这些属性进行操作的时候,为了在操作前后,保持一些特定条件不变(就是不准越界操作),所以就有了特性来约束它。
来看一下官方文档给的例子:
官方文档中提到:一个典型的例子就是托管x(这里的x是一个类的属性), 使用方法也特别的直接明了:如果 c 为 C 的实例,c.x
将调用 getter,c.x = value
将调用 setter, del c.x
将调用 deleter。就是在对c.x这个属性进行操作时,可以通过getter,setter,delx来控制它的修改和删除。
特性的用法
因为它是一个修饰器,所以调用方法有两种:
1.直接使用@符号调用
class Dog:
def __init__(self):
self.__name = None
@property
def name(self):
print('调用了get_name方法...')
return self.__name
@name.setter
def name(self, val):
print('调用了set_name方法...')
self.__name = val
@name.deleter
def name(self):
print('调用了del_name方法...')
del self.__name
if __name__ == '__main__':
tom = Dog()
tom.name = 'Tom'
print(tom.name)
del tom.name
2.当做一个正常的函数使用
class Cat:
def __init__(self):
self.__name = None
def set_name(self, name):
print('调用了set_name方法...')
self.__name = name
def get_name(self):
print('调用了get_name方法...')
return self.__name
def del_name(self):
print('调用了del_name方法...')
del self.__name
name = property(get_name, set_name, del_name, 'this is a property name.')
if __name__ == '__main__':
tom = Cat()
tom.name = 'Tom'
print(tom.name)
del tom.name
可以看到两种方法使用的效果都是一样的!
特性的使用场景
重点讲一下这个,正是因为有一些特定场景的存在,才会出现property这个特性的,正如之前在《Django企业开发实战》一书中所说的那样:若无必要,勿增实体。而python向来以简洁优雅著称,因为这些特定场景,所以是有必要增加property这个实体的。
主要使用场景有两个:
1.限制一些属性为只读
在只使用@property修饰某个方法后,将其变成特定的属性,如果不添加setter和deleter方法,那么它就变成了只读属性。比如:用户名设置后就不允许修改:
class User:
def __init__(self, username, password):
self.__username = username
self.password = password
# 将username属性限定为只读
@property
def username(self):
return self.__username
if __name__ == '__main__':
tom=User('tom','1234')
print(tom.username)
tom.username='Tom'
可以看到在只读状态下,修改和删除属性都会失败!
2.限定属性的操作范围
生活中,你可能会遇到这样的情况,有一天你告诉你妈你想吃鱼,并且是红烧鱼而不是清蒸鱼,然后你妈命令你爸去买鱼,同时你妈嘱咐你爸说:买新鲜一点的啊,价格贵一点没关系!然后你爸心想:这个月工资还没发呢,能省省就省省吧,于是你爸在心中就大概确定了买一条鱼的开销区间(比如30到100)。可以看到在一条鱼上餐桌之前,你和你爸妈是对它进行了精挑细选,才得以上到你的餐桌,其实就是对鱼这个属性增加了一些条件限定:类型的限定:要红烧的而不是清蒸的;取值范围的限定:不能太贵也不能太便宜,30到100之前刚刚好。
接下来用代码实现一下这个栗子:
class Fish:
def __init__(self):
self.__price = None
self.__cook = None
@property
def price(self):
return self.__price
@price.setter
def price(self, pri):
if not isinstance(pri, int):
raise ValueError('价格有误!')
if pri < 30:
raise ValueError('太便宜了,不要!')
elif pri > 100:
raise ValueError('太贵了,不要!')
else:
self.__price = pri
print('价格刚刚好!')
@property
def cook(self):
return self.__price
@cook.setter
def cook(self,method):
if method!='红烧':
raise ValueError('我只要红烧鱼!')
else:
print('耶,我最爱的红烧鱼!')
if __name__ == '__main__':
luck_fish=Fish()
luck_fish.price=60
# luck_fish.cook='清蒸'
luck_fish.cook='红烧'
可以看到,只有当属性的取值返回和类型是规定的范围之内的时候,程序才会正常执行,而生活中类似这样的栗子很多,所以这也是特性存在的意义。
属性和特性之间的差别和联系
直观的看,特性的目的好像是把方法“属性化”,但这样做一点意义也没有,如果我可以定义一个属性,何必再额外定义一个方法,然后将其转化成属性呢?所以,更重要的目的就是应对一些特定场景。
从特性表现出来的性质和行为来看,它其实就是一种特定的“属性”。只不过特性的权利提升了一点点,就好像你可以去修改这个属性,但是能不能修改成功,就看你的上一级允不允许你修改(有没有给你这个属性添加限定条件),而特性的权利就扩展到了这个“上一级”。
属性和特性之间的优先权
在写程序的时候,也不乏会出现这样的例子:属性和特性之间重名了!那么这个时候在使用这个重名的属性(特性)时,程序是会报错?还是会使用属性的值?还是会使用特性的值?也许根据它们的名称就可以猜出来,特性嘛,肯定就特别一些嘛,所以会优先使用特性的值!下面这个栗子完美说明:
# 关系:在同名的情况下,实例属性会覆盖类属性,特性会覆盖实例属性
class Cat:
@property
def wow(self):
return 'property---喵~'
if __name__ == '__main__':
# 实例属性会覆盖类属性
jerry = Cat()
# 特性会覆盖实例属性
print(jerry.__dict__) # 查看对象的属性字典
jerry.__dict__['wow'] = 'normal---喵~'
print(jerry.__dict__)
print(jerry.wow) # 虽然修改了jerry的wow的值,但是依旧返回的是其特性的值
print(jerry.__dict__['wow'])
del Cat.wow # 删除类特性后,返回的就是正常的属性值
# del Cat.wow # 删除特性
print(jerry.wow)
Cat.wow = property(lambda self: 'add a property---喵~') # 为类新增和属性同名的特性
print(jerry.wow) # 之后还是优先访问特性的值
来源:https://blog.csdn.net/max_LLL/article/details/125784537
猜你喜欢
- 其实网上已经有许多python语言书写的串口,但大部分都是python2写的,没有找到一个合适的python编写的串口助手,只能自己来写一个
- 我就废话不多说了,大家还是直接看代码吧~</pre><pre code_snippet_id="1947416&
- TensorFlow 2.0之后动态分配显存import tensorflow as tfconfig = tf.compat.v1.Con
- 装饰器对与Python新手以至于熟悉Python的人都是一个难理解, 难写的东西. 那么今天就分享一下我对Python 装饰器的理解所谓装饰
- javascript sort()排序用法sort() 方法用于对数组的元素进行排序,并返回数组。默认排序顺序是根据字符串UniCode码。
- 最近经常遇到xmlHttp组件的问题, 今天终于有空将解决过程中的经验整理下来了! ^o^一、在运用xmlhttp组件编
- 使用celery在django项目中实现异步发送短信在项目的目录下创建celery_tasks用于保存celery异步任务。在celery_
- 本文实例讲述了Python实现桶排序与快速排序算法结合应用的方法。分享给大家供大家参考,具体如下:#-*- coding: UTF-8 -*
- 一个单步的动作,用了这个脚本,就可以重复执行100遍1000遍。上面就是一个路径描边100遍的效果,吼吼~ 不知道大家明白用处没有?(以前老
- 环境系统:win10cpu:i7-6700HQgpu:gtx965mpython : 3.6pytorch :0.3数据下载来源自Sasan
- 本文实例讲述了python避免死锁方法。分享给大家供大家参考。具体分析如下:当两个或者更多的线程在等待资源的时候就会产生死锁,两个线程相互等
- 本文实例总结了Python常用的小技巧。分享给大家供大家参考。具体分析如下:1. 获取本地mac地址:import uuidmac = uu
- 在ASP中,直接使用“Insert into” 语句与使用ADO中AddNew方法有什么区别?哪一种更好呢?AddNew方法的实质就是封装了
- 主键的生成方式主要有三种: 一. 数据库自动生成 二. GUID 三. 开发创建 严格讲这三种产生方式有一定的交叉点,其定位方式将在下面进行
- 本文实例讲述了Python装饰器用法与知识点。分享给大家供大家参考,具体如下:(1)装饰器含参数,被装饰函数不含(含)参数实例代码如下:im
- SQL防注入代码一<?php /** * 防sql注入 * @author: zhuyubing@gmail.com * */ /**
- 一、概念 1. 数据库 (Database)什么是数据库?数据库是依照某种数据模型组织起来并存放二级存储器中的数据集合。这种数据集合具有如下
- 我还我还是有必要改一个标题,(原题为 让你想不通的"bug"),以免有同学误会。先看代码。看完之后我有个问题提问一下,看
- 这个问题对于规模稍微大些的项目而言,显得尤其重要了,数据库中如果有几百个存储过程, 难道还一个个找不成,即使自己很了解业务和系统,时间长了,
- 各位工程师累了吗? 推荐一篇可以让你技术能力达到出神入化的网站"持久男"1.二维绘图a. 一维数据集用 Numpy nd