代码之家  ›  专栏  ›  技术社区  ›  snoopy91

使用Python描述符:如何最好地编写通用验证getter-setter

  •  2
  • snoopy91  · 技术社区  · 11 年前

    最好的说法是,我指的是Python和尽可能少的代码行。

    我习惯于在Python中定义具有属性的类,就像这样。

    class MyClass(object):
    
        def __init__(self):
            self.value = 5
    

    然而,我经常发现自己需要确保 self.value 只能采用特定类型的值。在过去(来自PHP OOP背景),我曾使用类似于以下的getter-setter方法来完成此操作:

        def value(self, new_value = -1)
            if new_value == -1:
                return self.value
            if isinstance(new_value, int) and new_value > -1:
                self.value = new_value
            else:
                raise TypeError
    

    然后我访问 自我价值 具有 self.value() ,并设置为 self.value(67) .通常我会给芒果取名字 自我价值 self.__value 以阻止其直接访问。

    我最近发现了(或者正在发现)描述符。密切关注 excellent discussion here 我写了这样的东西:

    class ValidatedAttribute(object):
    
        def __init__(self, key, kind):
            self.key = key
            self.kind = kind
    
        def __get__(self, instance, owner):
            if self.key not in instance.__dict__:
                raise AttributeError, self.key
            return instance.__dict__[self.key]
    
        def __set__(self, instance, value):
            if not isinstance(value, self.kind):
                raise TypeError, self.kind
            instance.__dict__[self.key] = value     
    
    
    class MyUsefulClass(object):
    
        a = ValidatedAttribute("a", int)
    

    但我有几个问题!

    首先,到底是什么 MyUsefulClass().a ? 它是否是ValidatedAttribute类的实例,以某种方式绑定到 MyUsefulClass

    其次,我真正想要的是,

    class MyUsefulClass(object):
    
        def __init__(self):
            self.value = Checker(int, 99)
    
        def Checker(self, kind, default):
            # Code for verifying that associated attribute is of type kind.
    

    并以某种方式将属性访问绑定到某种拦截方法,而不必使用整个其他描述符类。

    如果我缺乏理解,我很抱歉——我仍在掌握新型Python类。如有任何帮助或指示,我们将不胜感激。

    5 回复  |  直到 9 年前
        1
  •  1
  •   Ethan Furman    11 年前

    首先,MyUsefulClass().a到底是什么?它是ValidatedAttribute类的实例吗?它以某种方式绑定到MyUsefulClass类的实例?

    是的,就是这样。

    其次,我真正想要的是像[…]这样的东西,并以某种方式将属性访问绑定到某种拦截方法,而不必使用整个其他描述符类。

    好吧,你可以改写 __getattribute__ ,因为它确实接受了 每一个 属性查找,但它比使用描述符要复杂得多。

    描述符正是为您想要做的事情工作(自动验证)。你能做的唯一改进是使用元类自动为你设置密钥,然后你的类代码看起来是这样的:

    class MyUsefulClass(object):
    
        a = ValidatedAttribute(int)
    

    但首先要熟悉描述符,元类很复杂,很难找到。

    哦,还有一个小小的改变 ValidatedAttribute :

    def __init__(self, key, default):
    
        self.key = key
        self.kind = type(default)
        self.default = default
    
    def __get__(self, instance, owner):
        if self.key not in instance.__dict__:
            return self.default
        return instance.__dict__[self.key]
    
        2
  •  1
  •   Veedrac    11 年前

    请,请,请不要这样做 isinstance(new_value, int) .

    可以 可能地 未受惩罚

    from numbers import Integral
    isinstance(new_value, Integral)
    

    但回避打字是完全令人厌恶的。

    首先,MyUsefulClass().a到底是什么?它是ValidatedAttribute类的实例吗?它以某种方式绑定到MyUsefulClass类的实例?

    为了找到 MyUsefulClass().a ,Python询问该类。类告诉它有一个属性的getter-setter,并告诉Python询问属性。属性表示找到它,然后告诉类该属性是什么。该属性不是getter-setter。

    MyUsefulClass.a 是getter setter(属性),而不是 MyUsefulClass().a .

    其次,我真正想要的是类似的东西

    AFAIK,您只能在类上设置财产,而不能在实例上设置,因为您如何知道要检索属性还是属性阴影的项?

        3
  •  1
  •   Marcin    11 年前

    与其自己写这些东西,不如使用特征库: https://pypi.python.org/pypi/traits 使用库是解决大多数问题的Python方法。

    然而,一般来说,您应该编写足够通用的代码,这样这种检查在很大程度上是不必要的。在python中很容易做到。

        4
  •  0
  •   Community CDub    7 年前

    我想你要找的是python财产。 Correct approach to validate attributes of an instance of class 似乎与你的推理有关。你也可以看看 Python descriptor vs property

        5
  •  0
  •   GP89    11 年前

    听起来你想用财产

    class MyUsefulClass(object):
    
        def __init__(self):
            self._value = 0
    
        @property
        def value(self):
            return self._value
    
        @value.setter
        def value(self, value):
            self._value = self.Checker(value, int, 99)
    
        def Checker(self, value, kind, default):
            return value if isinstance(value, kind) else default