Anu*_*dra 7 python python-2.7 python-3.x python-decorators python-object
请考虑以下代码
class DataMember():
def __init__(self, **args):
self.default = {"required" : False , "type" : "string" , "length": -1}
self.default.update(args)
def __call__(self , func):
#Here I want to set the attribute to method
setattr(func , "__dbattr__" , self.default)
def validate(obj , value):
#some other code
func(obj , value)
return validate
Run Code Online (Sandbox Code Playgroud)
这是我的装饰器方法来装饰其他类的属性的setter方法,我想为方法设置一些属性.但它不允许我.
我尝试如下
class User(DbObject):
def __init__(self):
super(User , self)
self._username = None
@property
def Name(self):
return self._username
@Name.setter
@DataMember(length=100)
def Name(self , value):
self._username = value
u = User()
u.Name = "usernameofapp"
print(u.Name)
print(u.Name.__dbattr__)
Run Code Online (Sandbox Code Playgroud)
运行此时出现以下错误
Traceback (most recent call last):
File "datatypevalidator.py", line 41, in <module>
print(u.Name.__dbattr__)
AttributeError: 'str' object has no attribute '__dbattr__'
Run Code Online (Sandbox Code Playgroud)
我做错了什么,如何为setter方法设置一些属性.
好的,这里有三点困惑.对象标识,描述符协议和动态属性.
首先,你要分配__dbattr__
给func
.
def __call__(self , func):
func.__dbattr__ = self.default # you don't need setattr
def validate(obj , value):
func(obj , value)
return validate
Run Code Online (Sandbox Code Playgroud)
但是,这是分配属性func
,然后只举行一员的validate
这反过来取代func
的类(这是装修做最终,更换另一个功能).因此,通过放置此数据func
,我们将失去对它的访问权限(没有一些严重的hacky __closure__
访问).相反,我们应该把数据放在上面validate
.
def __call__(self , func):
def validate(obj , value):
# other code
func(obj , value)
validate.__dbattr__ = self.default
return validate
Run Code Online (Sandbox Code Playgroud)
现在,u.Name.__dbattr__
有效吗?不,您仍然会收到相同的错误,但现在可以访问数据了.要找到它,我们需要了解python的描述符协议,它定义了属性的工作方式.
阅读链接的文章,全explination但有效,@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__
不是u.Name
(这是的结果User.Name.__get__(u, User)
,但是,User.Name.fset
方法本身!如果你想它(硬),这是有道理的,这是方法,你把它放在你没有把它放在结果的价值!
User.Name.fset.__dbattr__
Out[223]: {'length': 100, 'required': False, 'type': 'string'}
Run Code Online (Sandbox Code Playgroud)
是的,所以我们可以看到这些数据存在,但它不在我们想要的对象上.我们如何将它放到那个对象上?嗯,实际上非常简单.
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
Run Code Online (Sandbox Code Playgroud)
这只有在最终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'}
Run Code Online (Sandbox Code Playgroud)
您可能想知道为什么我使用自定义字符串类.好吧,如果您使用基本字符串,您将看到问题
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__'
Run Code Online (Sandbox Code Playgroud)
str
像python中的大多数内置类型一样,对象不允许随机属性赋值,如自定义python类(collections.UserString
是一个允许随机赋值的字符串的python类包装器).
所以最终,如果你最初想要的东西最终是不可能的.但是,使用自定义字符串类就可以了.
归档时间: |
|
查看次数: |
244 次 |
最近记录: |