如何在python中获取属性setter方法的属性

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方法设置一些属性.

FHT*_*ell 8

好的,这里有三点困惑.对象标识,描述符协议和动态属性.

首先,你要分配__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,fsetfdel方法,其是对您在类中定义的方法的引用.

因此,我们可以找到你__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类包装器).

所以最终,如果你最初想要的东西最终是不可能的.但是,使用自定义字符串类就可以了.