python类中的不可变属性和类型检查
Posted
技术标签:
【中文标题】python类中的不可变属性和类型检查【英文标题】:Immutable attribute in python class and type check 【发布时间】:2018-01-12 22:08:11 【问题描述】:我正在寻找一种在 python 中构建类的方法:
setter 在赋值前检查值的类型 无法添加新的类属性暂时我找到了这两个装饰器:
def getter_setter_gen(名称,类型_): def getter(自我): 返回 getattr(self, "__" + name) def setter(自我,价值): 打印“二传手”,价值 如果不是 isinstance(value, type_): raise TypeError("%s 属性必须设置为 %s 的实例" % (name, type_)) setattr(自我,“__”+名称,值) 返回属性(getter,setter) def auto_attr_check(cls): new_dct = 打印“auto_attr_check”,cls.__dict__.items() 对于 cls.__dict__.items() 中的键、值: 如果是实例(值,类型): 值 = getter_setter_gen(键,值) new_dct[键] = 值 # 创建一个新类,使用修改后的字典作为类字典: n = type(cls)(cls.__name__, cls.__bases__, new_dct) 返回 n和
def froze_it(cls): def freezesetattr(self, key, value): 打印键 键=''+键 打印(目录(自我)) 打印键 如果没有 hasattr(self, key): raise TypeError("Class 被冻结。无法设置 = " .format(cls.__name__, 键, 值)) 别的: object.__setattr__(self, key, value) cls.__setattr__ = freezesetattr 返回 cls但是我在加入这两种方法时遇到了很多麻烦。 你能帮助我吗?你有想法吗? 非常感谢
【问题讨论】:
【参考方案1】:您遇到的问题是您的property
正在使用setattr
来设置您的属性值,但是您已经覆盖了__setattr__
,以至于它永远不会成功。 hasattr
对主属性名称和作为属性基础的实际属性的下划线前缀名称的检查都将失败(如果设置器代码可以达到那么远)。
我建议两个互补的修复。首先,将hasattr
检查更改为更加小心。如果失败,它还应该检查属性对象的类字典:
def frozensetattr(self, key, value):
if not hasattr(self, key) and type(cls.__dict__.get(key)) is not property:
raise TypeError("Class is frozen. Cannot set = "
.format(cls.__name__, key, value))
else:
object.__setattr__(self, key, value)
第二个修复是 setter
函数,它应该绕过底层属性的 __setattr__
方法:
def setter(self, value):
print "setter", value
if not isinstance(value, type_):
raise TypeError("%s attribute must be set to an instance of %s" % (name, type_))
object.__setattr__(self, "__" + name, value)
最后一点:property
创建的属性名称上的双下划线前缀不会调用名称修改,我怀疑这是您的意图。名称修改仅在编译时发生。当方法包含像 __bar
这样的名称时,编译器会将名称转换为 _NameOfTheClass__bar
(其中 NameOfTheClass
是定义该方法的类的名称)。
在运行时,代码的行为与修改后的名称直接写入源代码一样。这意味着__setattr__
和朋友不会以任何特殊方式处理错误名称(或双下划线前缀名称,如果它们被编写为常规变量名称而不是字符串,编译器会对其进行错误处理)。所以没有简单的方法来对动态创建的变量进行名称修改。
如果您只想将您的名字非正式地标记为私有(也就是说,它们不是公共 API 的一部分),您可能应该使用单个前导下划线。
【讨论】:
以上是关于python类中的不可变属性和类型检查的主要内容,如果未能解决你的问题,请参考以下文章