当前位置: 首页 > news >正文

Python Cookbook-6.3 限制属性的设置

任务

通常情况下,Python 允许你随意给类和类实例增加属性。但对于某些特定的类,你却希望这种自由受到限制。

解决方案

特殊方法__setattr__会解读对属性的设置操作,它让你有机会限制新属性的添加。种优雅的实现方法是写一个类和一个简单的自定义元类,再加上一个封装函数,像下面这样:

def no_new_attributes(wrapped_setattr):'''试图添加新属性时,报错但允许已经存在的属性被随意设置'''def __setattr__(self,name,value):if hasattr(self,name):#非新属性,允许wrapped_setattr(self,name,value)#新属性,禁止else:raise AttributeError("can't add attribute %r to %s" %(name,self)return setattr
class NoNewAttrs(object):'''NoNewAttrs的子类会拒绝新属性的添加但允许已存在的属性被赋予新值'''#向此类的实例添加新属性的操作被屏蔽__setattr__ = no_new_attributes(object.__setattr__)class __metaclass__(type):'''一个简单的自定义元类,禁止向类添加新属性'''__setattr__ = no_new_attributes(type.__setattr__)

讨论

由于某些原因,有时你会想要限制 Python 的动态能力。比如,对于某个特定的类或其实例,有时你可能会意外地给它设置了新的属性,而你不希望这种情况发生。本节的解决方案介绍了怎样实现这样的限制。其要点是,不要为这个目的使用__siots__:__slots__ 应该被用于其他的任务(比如,你的类有一些固定的属性并有数量很多的实例,利用__slots__可以避免每个实例都拥有一个字典,从而节省很多内存)。__slots__应该被用来做它适合做的事,如果你试图用它来完成本节的任务,会遇到很多限制(见6.7节中一个使用__slots __来节省内存的例子)。

需要注意的是,本节解决方案给出的方法阻止了在运行时添加属性,而且不仅对类实例有效,对类本身也适用,这应该归功于那个简单的自定义元类。当你想要限制一些意外添加属性的行为时,你通常会希望类和它的每个实例都受到限制。另一方面,类和类实例已经存在的属性则可以被随意地设置新值,下面给出一个使用这个类的例子:

class Person(NoNewAttrs):firstname = ''lastname = ''def __init__(self,firstname,lastname):self.firstname = firstnameself.lastname = lastnamedef __repr__(self):return 'Person'(%r,%r) %(self.firstname,self.lastname)
me = Person("Michere","Simionato")
print me
#输出:Person('Michere','Simionate')
#firstname的值是错的,能修正吗?当然没问题!
me.firstname = "Michele"
print me
#输出:Person('Michele',isimionato')

从 NoNewAttrs 继承将迫使你只能在类的内部“声明”那些允许被设置的属性。如果你想在进一步使用中设置一个“未声明”的属性,只会得到一个AttributeError:

try:Person.address = ''
except AttributeError,err:print 'raised %r as expected' %err
try:me.address = ''
except AttributeError,err:print 'raised %r as expected' %err

从某种意义上讲,NoNewAtr的子类以及它们的实例其实很像Java或 C++的类与实例,而不像普通的 Python 类和实例。因此,当你在用Python 构建某种原型而且最后会用其他动态性逊于Python的语言来重新编写代码的时候,本节提供的方法会很适合你的需求。

相关文章:

  • 正则表达式在线校验(RegExp) - 加菲工具
  • [LeetCode 1696] 跳跃游戏 6(Ⅵ)
  • Javascript逗号操作符
  • 【JavaScript】十九、页面尺寸事件 + 获取元素位置
  • (二十五)安卓开发一个完整的登录页面-支持密码登录和手机验证码登录
  • Android Studio 项目文件夹结构详解
  • Android WebView深度性能优化方案
  • UE5 Chaos :官方文献总结 + 渲染网格体 (Render Mesh) 和模拟网格体 是如何关联的?为什么模拟网格体 可以驱动渲染网格体?
  • CAD-MLLM 论文阅读笔记
  • [redis进阶二]分布式系统之主从复制结构(2)
  • 【LeetCode 热题 100】哈希 系列
  • 调节磁盘和CPU的矛盾——InnoDB的Buffer Pool
  • 安全人员如何对漏洞进行定级?
  • HTTP:六.HTTP代理相关介绍
  • 力扣HOT100——无重复字符的最长子字符串
  • route
  • 基于javaweb的SpringBoot影视播放评分交流系统设计与实现(源码+部署文档)
  • 【VsCode】设置文件自动保存
  • Mysql 身份认证绕过漏洞
  • Kotlin 集合过滤全指南:all、any、filter 及高级用法
  • 葛兰西:“生活就是抵抗”
  • 别让心脏“饿肚子”,心肌缺血全解析
  • 泽连斯基公布与特朗普会晤细节,强调实现全面、无条件停火
  • 特朗普政府称将恢复被终止的外国学生合法身份
  • 本周看啥|在电影院里听民谣,听摇滚,燥起来吧
  • 昆明一小区电梯突然从40楼降到负4楼,回应:临时断电引起