使用Python描述符:如何最好地编写通用验证getter setter
我所说的“最佳”是指以pythonical方式和尽可能少的代码行 我习惯于用Python中的属性定义类,就像这样使用Python描述符:如何最好地编写通用验证getter setter,python,oop,validation,descriptor,Python,Oop,Validation,Descriptor,我所说的“最佳”是指以pythonical方式和尽可能少的代码行 我习惯于用Python中的属性定义类,就像这样 class MyClass(object): def __init__(self): self.value = 5 然而,我经常发现自己需要确保self.value只能接受特定类型的值。在过去(来自PHP OOP背景),我使用了类似于以下内容的getter setter方法: def value(self, new_value = -1)
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
,并用self.value(67)
设置它。通常我会将mangleself.value
命名为self.\uu value
以阻止其直接访问
我最近发现了(或正在发现)描述符。紧随其后,我写了如下内容:
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)
class MyUsefulClass(object):
a = ValidatedAttribute(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类。如果您能提供任何正确的帮助或指导,我们将不胜感激。我想您需要的是python属性。似乎和你的想法有关。您还可以查看听起来您想使用属性
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
请,请,请不要执行
isinstance(新值,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
第二,我真正想要的是[东西]
好的,您只能在类上设置属性,而不能在实例上设置属性,因为您如何知道是要检索属性还是要检索属性阴影中的项
首先,MyUsefulClass().a到底是什么?它是ValidatedAttribute类的实例,以某种方式绑定到MyUsefulClass类的实例吗
是的,就是这样
其次,我真正想要的是像[…]这样的东西,并以某种方式将属性访问绑定到某种拦截方法,而不必使用整个其他描述符类
好的,您可以覆盖\uuu getattribute\uuuu
,就像它在每个属性查找中所做的那样,但是它比使用描述符复杂得多
描述符的作用正是您想要做的(自动验证)。您可以做的唯一改进是使用元类为您自动设置密钥,然后您的类代码如下所示:
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)
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]
与其自己写这些东西,不如使用traits库:。使用库是解决大多数问题的python方法
然而,一般来说,您应该编写足够通用的代码,以使这种检查基本上是不必要的。用python很容易做到这一点 有时duck类型不起作用:与其他语言、系统、数据库等交互。这就是为什么我们有
isinstance
。代码运行良好,您只需在尝试访问它之前分配一个值。“代码运行良好,您只需在尝试访问它之前分配一个值。”Teehee,您不会相信我为了得出结论而搞砸了什么;)。是的,忽略这一点。属性是我考虑过的东西,但我的问题是,它们必须以这种方式为每个要验证的属性显式定义getter和setter函数。这或多或少就像为每个“private”属性编写一个getter setter函数一样冗长,这就是我目前所做的。(也就是说,编写def myattr(self,value)
来获取和设置self.\uu myattr
)我选择这个答案是因为它向我介绍了\uuu getattribute\uuuuuu
,而我以前并不知道。我不认为这是最优雅的解决方案,但覆盖\uuuu getattribute\uuuu
肯定是解决我的问题最普遍、最不臃肿的解决方案,至少在我迄今为止找到的解决方案中是如此。