好的,所以这里有三点混淆。对象身份、描述符协议和动态属性。
首先,您分配__dbattr__
给func
.
def __call__(self , func):
func.__dbattr__ = self.default # you don't need setattr
def validate(obj , value):
func(obj , value)
return validate
但这是将属性分配给func
,然后仅将其作为一个成员保存,而该成员validate
又在类中替换func
(这是装饰器最终所做的,用另一个函数替换一个函数)。因此,通过将这些数据放在 上func
,我们将无法访问它(当然没有一些严重的黑客__closure__
访问)。相反,我们应该将数据放在validate
.
def __call__(self , func):
def validate(obj , value):
# other code
func(obj , value)
validate.__dbattr__ = self.default
return validate
现在,有用u.Name.__dbattr__
吗?不,您仍然会遇到相同的错误,但现在可以访问数据。要找到它,我们需要了解定义属性如何工作的 python描述符协议。
阅读链接的文章以获得完整的解释,但有效地@property
通过使用__get__
,__set__
和__del__
方法创建一个附加类来工作,当您调用inst.property
您实际所做的事情时调用它们inst.__class__.property.__get__(inst, inst.__class__)
(以及类似的inst.property = value --> __set__
和del inst.property --> __del__
()。这些中的每一个依次调用fget
,fset
和fdel
方法是对您在类中定义的方法的引用。
所以我们可以找到你的__dbattr__
not on (u.Name
这是方法本身的结果!如果你考虑一下(hard),这是有道理的。这是你穿上的方法。你没有穿上结果的价值!User.Name.__get__(u, User)
User.Name.fset
User.Name.fset.__dbattr__
Out[223]: {'length': 100, 'required': False, 'type': 'string'}
对,所以我们可以看到这个数据存在,但它不在我们想要的对象上。我们如何把它放到那个物体上?嗯,其实很简单。
def __call__(self , func):
def validate(obj , value):
# Set the attribute on the *value* we're going to pass to the setter
value.__dbattr__ = self.default
func(obj , value)
return validate
这仅在 setter 最终返回值时才有效,但在您的情况下它确实有效。
# Using a custom string class (will explain later)
from collections import UserString
u = User()
u.Name = UserString('hello')
u.Name # --> 'hello'
u.Name.__dbattr__ # -->{'length': 100, 'required': False, 'type': 'string'}
您可能想知道为什么我使用自定义字符串类。好吧,如果您使用基本字符串,您会看到问题
u.Name = 'hello'
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-238-1feeee60651f> in <module>()
----> 1 u.Name = 'hello'
<ipython-input-232-8529bc6984c8> in validate(obj, value)
6
7 def validate(obj , value):
----> 8 value.__dbattr__ = self.default
9 func(obj , value)
10 return validate
AttributeError: 'str' object has no attribute '__dbattr__'
str
对象,像 python 中的大多数内置类型一样,不允许像自定义 python 类那样的随机属性分配(collections.UserString
是允许随机分配的字符串的 python 类包装器)。
因此,最终,您最初想要的内容对于内置字符串是不可能的,但使用自定义类可以让您做到。