Python面向对象 | 类属性
property
property是一个装饰器函数,可以将一个方法伪装成属性,调用的时候可以不用加()。@property被装饰的方法,是不能传参数的,因为它伪装成属性了。
装饰器的使用:在要装饰的函数、方法、类上面一行加上 @装饰器名字
装饰器的分类:
- 装饰函数
- 装饰方法:property
- 装饰类
例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
体质指数(BMI)=体重(kg)÷身高^2(m)
EX:70kg÷(1.75×1.75)=22.86
查看我的BMI
class Person(object):
def __init__(self,name,weight,height):
self.name = name
self.__weight = weight
self.__height = height
@property
def bmi(self):
return self.__weight / self.__height **2
p = Person('xiao',65,1.75)
print(p.bmi) # 21.224489795918366
print(Person.__dict__)
print(p.__dict__) # 在对象里面,并没有被当成属性
'''
执行输出:
21.224489795918366
{'__module__': '__main__', '__init__': <function Person.__init__ at 0x000002221B1EC048>, 'bmi': <property object at 0x000002221B1E8C78>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
{'name': 'xiao', '_Person__weight': 65, '_Person__height': 1.75}
'''
被property装饰的bmi仍然是一个方法,存在Person.__dict__。对象的.__dict__中不会存储这个属性.
下面的代码,也可以实现上面的效果
class Person(object):
def __init__(self,name,weight,height):
self.name = name
self.__weight = weight
self.__height = height
#self.bmi = self.__weight / self.__height **2
#self.bmi = cal_BMI()
# 但是计算的逻辑,不能放到init里面。初始化,不要做计算
举例:
class Person(object):
def __init__(self,name,weight,height):
self.name = name
self.__weight = weight
self.__height = height
self.bmi = self.__weight / self.__height **2
p = Person('xiao',65,1.75)
print(p.bmi)
p._Person__weight = 70 # 1周之后,增加体重
print(p.bmi)
'''
执行输出:
21.224489795918366
21.224489795918366
'''
执行结果是一样的,体重增加了,但是bmi指数没有变动。因为__init__初始化之后,就不会再变动了。
在__init__里面,属性名不能和方法名重复
class Person(object):
def __init__(self,name,weight,height,bmi):
self.name = name
self.__weight = weight
self.__height = height
self.bmi = bmi
def bmi(self):
return self.__weight / self.__height **2
a = Person('xiao',65,1.75)
print(a.bmi()) # TypeError: __init__() missing 1 required positional argument: 'bmi'
那么bmi是否可以修改呢?
class Person(object):
def __init__(self,name,weight,height):
self.name = name
self.__weight = weight
self.__height = height
@property
def bmi(self):
return self.__weight / self.__height **2
p = Person('xiao',65,1.75)
p.bmi = 2 # AttributeError: can't set attribute
但是它的name属性是可以改变的。
class Person:
def __init__(self,name):
self.name = name
p = Person('Tony')
print(p.name) # Tony
p.name = 'John'
p.name = 123
那么上面这2个例子,和直接定义name属性有什么区别?
class Person:
def __init__(self,name):
self.__name = name # 私有的属性
@property
def name(self):
return self.__name
def set_name(self,new_name):
if type(new_name) is str:
self.__name = new_name
else: # 通过if判断,就可以保护属性的类型,必须是字符串
print('您提供的姓名数据类型不合法')
p = Person('Tony')
print(p.name)
p.set_name('John')
print(p.name)
p.set_name(123)
'''
执行输出:
Tony
John
您提供的姓名数据类型不合法
'''
@property可以将python定义的函数“当做”属性访问,有时候setter/deleter也是需要的。
只有@property表示只读。
同时有@property和@x.setter表示可读可写。
同时有@property和@x.setter和@x.deleter表示可读可写可删除。
新式类中具有三种访问方式,分别将三个方法定义为对同一个属性:获取、修改、删除
class Foo:
@property
def AAA(self):
print('get的时候运行我啊')
@AAA.setter
def AAA(self,value):
print('set的时候运行我啊')
@AAA.deleter
def AAA(self):
print('delete的时候运行我啊')
#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA
'''
执行输出:
get的时候运行我啊
set的时候运行我啊
delete的时候运行我啊
'''
或者:
class Foo:
def get_AAA(self):
print('get的时候运行我啊')
def set_AAA(self,value):
print('set的时候运行我啊')
def delete_AAA(self):
print('delete的时候运行我啊')
AAA=property(get_AAA,set_AAA,delete_AAA) # 内置property三个参数与get,set,delete一一对应
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA
'''
执行输出:
get的时候运行我啊
set的时候运行我啊
delete的时候运行我啊
'''
商品实例
class Goods(object):
def __init__(self):
self.original_price = 100 # 原价
self.discount = 0.8 # 折扣
@property
def price(self): # 计算折后价格
new_price = self.original_price * self.discount
return new_price
@price.setter
def price(self, value):
self.original_price = value
@price.deleter
def price(self, value):
del self.original_price
obj = Goods()
print(obj.price) # 获取商品价格 80.0
obj.price = 200 # 修改商品原价
print(obj.price) # 获取商品价格 160.0
# del obj.price # 删除商品原价 TypeError: price() missing 1 required positional argument: 'value'
class Person:
def __init__(self,name):
self.__name = name # 私有的属性
@property
def name(self):
return self.__name
@name.setter
def name(self,new_name):
print('---',new_name)
p = Person('Tony')
p.name = 'John' # 修改name属性
'''
执行输出:
--- John
'''
上面的代码,3个name必须是相同的。三位一体。@name.settet有且并只有一个参数
class Person:
def __init__(self,name):
self.__name = name # 私有的属性
@property
def name(self):
return self.__name
@name.setter
def name(self,new_name):
print('---',new_name)
p = Person('Tony')
print(p.name)
p.name = 'John' # 修改name属性
print(p.name)
'''
执行输出:
Tony
--- John
Tony
'''
从结果上来看,并没有改变Tony的值那么如何改变呢?看下面的代码
class Person:
def __init__(self,name):
self.__name = name # 私有的属性
@property
def name(self):
return self.__name
@name.setter
def name(self,new_name):
self.__name = new_name # 更改__name属性
p = Person('Tony')
print(p.name)
p.name = 'John' # 修改name属性
print(p.name)
'''
执行输出:
Tony
John
'''
但是这样,不能保证修改的数据类型是固定的
class Person:
def __init__(self,name):
self.__name = name # 私有的属性
@property
def name(self):
return self.__name
@name.setter
def name(self,new_name):
if type(new_name) is str:
self.__name = new_name
else:
print('您提供的姓名数据类型不合法')
p = Person('Tony')
print(p.name)
p.name = 'John' # 修改name属性
print(p.name)
p.name = 123 # 不合法
print(p.name)
'''
执行输出:
Tony
John
您提供的姓名数据类型不合法
John
'''
非法类型,不允许修改,这样就可以保护属性的类型
方法伪装成的属性删除操作
class Person:
def __init__(self,name):
self.__name = name # 私有的属性
@property
def name(self):
return self.__name
p = Person('alex')
print(p.name)
del p.name # AttributeError: can't delete attribute
# 为什么不能删除?因为name被@property伪装了,此时name是只读的。
那么如何删除呢?看下面的代码
class Person:
def __init__(self,name):
self.__name = name # 私有的属性
@property
def name(self):
return self.__name
@name.deleter
def name(self):
del self.__name
p = Person('Tony')
print(p.name)
del p.name
print(p.__dict__) # 查看属性
'''
执行输出:
Tony
{}
'''
p对象返回的是空字典,说明删除成功了!
3个装饰器的重要程度
- @property****
- @name.setter ***
- @name.deleter *
再讲一个列子:商品的 折扣 我想看折后价
class Goods:
def __init__(self,name,origin_price,discount):
self.name = name
self.__price = origin_price # 原价
self.__discount = discount # 折扣价
@property
def price(self):
return self.__price * self.__discount
apple = Goods('apple',5,0.8)
print(apple.price) # 4.0
修改苹果的原价
class Goods:
def __init__(self,name,origin_price,discount):
self.name = name
self.__price = origin_price # 原价
self.__discount = discount # 折扣价
@property
def price(self): # 价格
return self.__price * self.__discount
@price.setter
def price(self,new_price):
if type(new_price) is int or type(new_price) is float:
self.__price = new_price
apple = Goods('apple',5,0.8)
print(apple.price) # 4.0
apple.price = 8 # # 修改苹果的原价
print(apple.price) # 6.4
被property装饰的方法,不能修改,只能查看
圆形类,有半径,面积,周长。要求:将方法伪装成属性,方法中一般涉及的都是一些计算过程
from math import pi
class Circle: # 圆形
def __init__(self, r):
self.r = r
@property
def area(self): # 面积
return pi * self.r ** 2
@property
def perimeter(self): # 周长
return pi * self.r * 2
c = Circle(10)
print(c.area)
print(c.perimeter)
c.r =15 # 修改半径
print(c.area)
print(c.perimeter)
'''
执行输出:
314.1592653589793
62.83185307179586
706.8583470577034
94.24777960769379
'''
总结:
@property --> func 将方法伪装成属性,只观看的事儿
@func.setter --> func 对伪装的属性进行赋值的时候调用, 一般情况下用来做修改
@func.deleter --> func 在执行del 对象.func的时候调用,一般情况下用来做删除.基本不用
property的作用:
将一些需要随着一部分属性的变化而变化的值的计算过程 从方法 伪装成属性
将私有的属性保护起来,让修改的部分增加一些约束,来提高程序的稳定性和数据的安全性
在一个类加载的过程中,会先加载这个类的名字,包括被property装饰的。
在实例化对象的时候,python解释器会先到类的空间里看看有没有这个被装饰的属性,如果有就不能再在自己对象的空间中创建这个属性了
Python面向对象 | 类属性的更多相关文章
- Python面向对象—类属性和实例属性
属性:就是属于一个对象的数据或函数元素 类有类方法.实例方法.静态方法.类数据属性(类变量)和实例数据属性(实例变量). 类属性:包括类方法和类变量,可以通过类或实例来访问,只能通过类来修改. 实例属 ...
- python 面向对象类成员(字段 方法 属性)
一.字段 字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同, 普通字段属于对象 静态字段属于类 class Province: # 静态字段 countr ...
- Python面向对象-类、实例的绑定属性、绑定方法和__slots__
绑定属性 从之前的文章中,我们知道python是动态语言——实例可以绑定任意属性. 那如果实例绑定的属性和类的属性名一样的话,会是什么情况呢? >>> class Student(o ...
- python面向对象——类
from:http://www.runoob.com/python3/python3-class.html Python3 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在P ...
- python面向对象(类和对象及三大特性)
类和对象是什么 创建类 新式类 和 经典类 面向对象三大特性 继承 封装 多态 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...
- Python面向对象之类属性类方法静态方法
类的结构 实例 使用面向对象开发时,第一步是设计类: 当使用 类名() 创建对象时,会自动执行以下操作: 1.为对象在内存中分配空间--创建对象: 2.为对象的属性 设置初始值--初始化方法(init ...
- ~~核心编程(二):面向对象——类&属性~~
进击のpython 类&属性 虽然我们上一part写了一个面向对象的程序:人狗大战 但是如果在面向对象来看 你这些的就不够规范 你既然选择用面向对象的思想来写 那你就要符合人家的定义规范和操作 ...
- Python——面向对象(类)的基础疑难点
相信用Python写def函数大家都信手拈来了,但Python作为面向对象的编程语言,怎么能浪费呢? 那问题来了.什么是类呢?什么是实例?什么是对象?方法是什么??属性又是什么???继承?封装?多态? ...
- python 添加类属性
类属性必须赋值. 创建类属性 类是模板,而实例则是根据类创建的对象. 绑定在一个实例上的属性不会影响其他实例,但是,类本身也是一个对象,如果在类上绑定一个属性,则所有实例都可以访问类的属性,并且,所有 ...
随机推荐
- HTML禁用Flash文件右键
在项目中遇到一个需求,由于制作Flash的同事没有做禁用Flash文件右键功能!而Flash文件比较多,一个个改不太现实,于是要求用在网页显示的时候禁用Flash右键功能!未禁用之前! 禁用之前: 禁 ...
- python运维开发常用模块(一)psutil
1.模块简介 psutil是一个跨平台库(http://code.google.com/p/psutil/),能够轻 松实现获取系统运行的进程和系统利用率(包括CPU.内存.磁盘.网 络等)信息.它主 ...
- RestTemplate使用教程
原文地址:https://www.cnblogs.com/f-anything/p/10084215.html 一.概述 spring框架提供的RestTemplate类可用于在应用中调用rest服务 ...
- xss之挑战小靶场(1-10)
在线靶场(http://xss.fbisb.com) w 第一关 get请求,没有什么过滤,直接上<script>alert()</script> 源码: 第二关 输入参数会显 ...
- Clean Code 笔记 之 第二章
你是否真正的会命名 前言 这是我第二次看这本书了(Clean Code)的时候,第一次看的时候是,看到某世界五百强在他们的代码中我竟然看不到一句注释,现在我还记得当时的情景,当我Download 下第 ...
- python的import和form...import的区别
import和form...import的区别 参考链接 骏马金龙 https://www.cnblogs.com/lzc978/p/10105194.html 普通区别 import 使用impor ...
- ISO C语言新标准(C11)
新特性[2]有些和C++11是对应的,如线程和UTF-8: 对齐处理(Alignment)的标准化(包括_Alignas标志符,alignof运算符, aligned_alloc函数以及<std ...
- ElasticSearch6.3.2 集群做节点冷(warm) 热(hot) 分离
拿一个小规模的5节点ES集群做冷热分离尝试,它上面已经有60多个索引,有些索引按月.每月生成一个索引,随着数据的不断写入,历史数据(只需保留三个月数据,三个月之前的数据视为历史数据)越来越占磁盘空间和 ...
- 【3】hexo+github搭建个人博客的主题配置
更换博客主题 主题可参考:https://hexo.io/themes/ hexo默认主题:Landscape 示例主题:Next 下载Next主题 进入Blog所在目录,输入下载命令 #进入Blog ...
- Consider the following: If you want an embedded database (H2, HSQL or Der...
这个坑把java进程干掉就可以了,因为占用了 Description: Failed to configure a DataSource: 'url' attribute is not specifi ...