【问题标题】:Immutable attribute in python class and type checkpython类中的不可变属性和类型检查
【发布时间】: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

但是我在加入这两种方法时遇到了很多麻烦。 你能帮助我吗?你有想法吗? 非常感谢

【问题讨论】:

    标签: python class decorator


    【解决方案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 的一部分),您可能应该使用单个前导下划线。

    【讨论】:

      猜你喜欢
      • 2011-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-06
      • 2019-02-11
      • 1970-01-01
      • 2019-09-29
      • 2016-12-11
      相关资源
      最近更新 更多