我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈
入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈
虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈
PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈
Oracle数据库教程:👉👉 Oracle数据库文章合集 👈👈
优 质 资 源 下 载 :👉👉 资源下载合集 👈👈
类&补充_只读属性
- 只读属性
- 概念
- 应用场景
- 实现方法
- 方式一:使用property装饰器
- 方式二:使用__setattr__方法进行判断
- 补充_装饰器property详解
- property作用
- property源码
- 补充:经典类和新式类
- property在两种类中的使用方式
- property在新式类中的使用方式
- property在经典类中的使用方式(在Python2.x版本中运行)
只读属性
概念
- 一个属性(一般指实例属性),只能读取,不能写入
应用场景
- 有些属性,只限在内部根据不同场景进行修改,对外界来说,不能修改,只能读取
实现方法
方式一:使用property装饰器
- 步骤
- 1、通过私有化全部隐藏(既不能读,也不能写)
- 2、通过方法部分公开(公开读的操作)
- 示例
class Person:def __init__(self):self.__age = 18def getAge(self):return self.__agep = Person()# print(p.__age) # 报错,通过属性私有化,隐藏了读操作 # p.__age = 22 # 并不是修改的私有属性,而是新增了__age属性。通过属性私有化,隐藏了写操作print(p.getAge()) # 通过指定方法,公开读操作
- 存在问题
- 1、获取属性的时候需要通过调用方法获取
p.getAge()
,而不是通过属性获取方式获取p.age
- 2、在外部直接使用赋值
p.age = 22
并不会报错(虽然没有修改内部的私有属性,而是给实例添加了一个age属性,但是给人的感觉就是修改了)
- 1、获取属性的时候需要通过调用方法获取
- 优化
class Person:def __init__(self):self.__age = 18# @property的作用:装饰器,可以使用属性的方式调用这个方法@propertydef age(self):return self.__agep = Person()print(p.age) # 18 # p.age = 22 # 报错,AttributeError: can't set attribute
- 通过优化之后,就可以通过调用属性的方式调用读属性方法了。并且,外部也不能对这个属性方法进行赋值
- 缺陷
- 通过装饰器的方式设置的只读属性,其实还是可以通过
_Person__age
这种改名之后的方式进行修改 - 也可以通过
实例.__dict__['_Person__age'] = 新值
的方式修改这个只读属性的值
- 通过装饰器的方式设置的只读属性,其实还是可以通过
方式二:使用__setattr__方法进行判断
- 步骤
- 当通过 实例.属性=值 的方式给实例添加一个属性或修改属性的值时候,会自动调用该方法
- 在这个方法内部,增加判定方法,满足条件后才把这个属性添加到
__dict__
这个字典中
- 代码说明
class Person(object):# 当通过 实例.属性=值 的方式给实例添加一个属性或修改属性的值时候,会自动调用该方法# 在这个方法内部,才会真正的把这个属性添加到 __dict__ 这个字典中def __setattr__(self, key, value):# key:属性 value:属性值print(key, value)p = Person() p.age = 12 # age 12
- 使用
__setattr__
设置只读属性class Person(object):def __init__(self):self.__age = 18pass@propertydef age(self):return self.__age# 当通过 实例.属性=值 的方式给实例添加一个属性或修改属性的值时候,会自动调用该方法# 在这个方法内部,才会真正的把这个属性添加到 __dict__ 这个字典中def __setattr__(self, key, value):# key:属性 value:属性值# print(key, value)if key == 'age':print('隐藏属性,不可修改', key)return# self.key = value# 不能这么写,这样写也是通过 实例.属性=值 的方式给实例添加一个属性或修改属性的值,会循环调用__setattr__方法,出现死循环# 只能通过下面的方法给实例添加/修改属性self.__dict__[key] = valuep = Person() print(p.age) # 18 p.age = 22 # 隐藏属性,不可修改 age print(p.age) # 18
补充_装饰器property详解
property作用
- 将一些“属性的操作方法(删、改、查)”关联到某一个属性中
class Person(object):def __init__(self):self.__age = 18@property def age(self, num):"""属性的操作方法:获取属性值"""return self.__age
property源码
- preoperty源码说明
class property(object):"""Property attribute.property(fget=None, fset=None, fdel=None, doc=None) -> property ottribute# 调用property函数,传入四个参数,返回一个属性# 作用:将一个属性的几个操作方法(删、改、查)关联到返回的这个属性里面# 读取这个属性的时候会自动调用第一个参数:fget方法# 设置这个属性的值会自动调用第二个参数:fset方法# 删除合格属性的时候会自动调用第三个参数:fdel方法fgetfunction to be used for getting an attribute value# 用于获取属性值的函数fsetfunction to be used for setting an attribute value# 用于设置属性值的函数fdelfunction to be used for del'ing an attribute# 用于删除属性值的函数docdocstringTypical use is to define a managed attribute x:# 典型的用法是定义一个定义和管理一个属性x:class C(object):def getx(self): return self._xdef setx(self, value): self._x = valuedef delx(self): del self._xx = property(getx, setx, delx, "I'm the 'x' property.")Decorators make defining new properties or modifying existing ones easy:# 装饰器使定义新属性或修改现有属性变得容易:class C(object):@propertydef x(self):"I am the 'x' property."return self._x# 必须先开启上面的@property装饰器@x.setterdef x(self, value):self._x = value@x.deleterdef x(self):del self._x"""
补充:经典类和新式类
- 经典类
- 概念:没有继承自object的类
- 新式类
- 概念:继承自object的类和其派生类
- 示例
# 在Python2.x 版本中 class Person:passclass Animal(object):pass# 查看基类(父类) print(Person.__base__) # () print(Animal.__base__) # <class 'object'># ===================================================# 在Python3.x 版本中 class Person:passclass Animal(object):pass# 查看基类(父类) print(Person.__base__) # <class 'object'> print(Animal.__base__) # <class 'object'>
- 在Python2.x版本中
- 定义一个类的时候,没有显示的继承自object类,那么这个类就是一个经典类
- 必须显示的继承自object类,才是一个新式类
- 在Python3.x版本中
- 定义一个类的时候,没有显示的继承自pbject类时,会隐式的(默认)继承自object类,这个类就是一个新式类
- 在通常情况下,我们一般都写成显示继承(即:定义的类继承自object时,也用
class Person(object)
的方式定义)
property在两种类中的使用方式
property在新式类中的使用方式
- 使用方式一
class Person(object):def __init__(self):# 定义一个属性__ageself.__age = 18def get_age(self):"""定义一个__age属性的操作方法(查)"""print('执行get_age方法')return self.__agedef set_age(self, num):"""定义一个__age属性的操作方法(改)"""print('执行set_age方法')self.__age = num# 调用property方法,使age属性与get_age、set_age方法进行关联# 在获取age属性的值时,自动调用property函数的第一个参数:get_age方法# 在设置age属性的值时,自动调用property函数的第二个参数:seg_age方法age = property(get_age, set_age)p = Person() print(p.age) # 执行get_age方法 18p.age = 36 # 执行set_age方法 print(p.age) # 执行get_age方法 36print(p.__dict__) # {'_Person__age': 36},可以看出来,赋值方式并没有给对象增加新的属性,而是直接修改了原本的属性值
- 使用方式二
class Person(object):def __init__(self):self.__age = 18@propertydef age(self):print("执行了@property装饰的age方法")return self.__age@age.setterdef age(self, num):print("执行了@age.setter装饰的age方法")self.__age = num@age.deleterdef age(self):print("执行了@age.deleter装饰的age方法")del self.__agep = Person() print(p.age) # 执行了@property装饰的age方法 18p.age = 36 # 执行了@age.setter装饰的age方法print(p.__dict__) # {'_Person__age': 36}del p.age # 执行了@age.deleter装饰的age方法
property在经典类中的使用方式(在Python2.x版本中运行)
- 使用方式一
# Python2.x版本运行 # 定义一个经典类,不继承自object类 class Person:def __init__(self):self.__age = 18def get_age(self):print '执行了get_age方法'return self.__agedef set_age(self, num):print '执行了set_age方法'self.__age = numage =property(get_age, set_age)p = Person() print p.age # 执行了get_age方法p.age = 36 # print(p.__dict__) # {'age': 36, '_Person__age': 18}# 可以看出来,在经典类中,属性的赋值操作并不能关联到property函数的第二个参数
- 使用方式二
# Python2.x版本运行 # 定义一个经典类,不继承自object类 class Person:def __init__(self):self.__age = 18@propertydef age(self):print '执行了get_age方法'return self.__age@age.setterdef age(self, num):print '执行了set_age方法'self.__age = nump = Person() print p.age # 执行了get_age方法 18p.age = 36 #print(p.__dict__) # {'age': 36, '_Person__age': 18}
- 通过示例可以看出来,在经典类中,虽然我们可以定义装饰属性赋值操作的方法,但是并不能真正的将这个操作方法与赋值操作进行关联