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

标签 python python-3.x python-2.7 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

这是我的装饰方法来装饰其他类的属性的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__)

运行时出现以下错误

Traceback (most recent call last):
File "datatypevalidator.py", line 41, in <module>
print(u.Name.__dbattr__)
AttributeError: 'str' object has no attribute '__dbattr__'

我做错了什么,我怎样才能将一些属性设置为 setter 方法。

最佳答案

好吧,这里有三点混淆。对象标识、描述符协议(protocol)和动态属性。

首先,您要分配 __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 上,我们失去了对它的访问权限(没有一些严重的 hacky __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的descriptor protocol它定义了属性如何工作。

阅读链接文章以获得完整的解释,但有效,@property通过使用 __get__ 创建一个额外的类来工作, __set____del__当您调用 inst.property 时使用的方法你实际上做的是打电话inst.__class__.property.__get__(inst, inst.__class__) (与 inst.property = value --> __set__del inst.property --> __del__ () 类似。它们中的每一个依次调用 fgetfsetfdel 方法,这些方法是对您在类中定义的方法的引用。

所以我们可以找到您的 __dbattr__不在 u.Name (这是 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 类包装器,它允许随机分配字符串)。

因此最终,您最初想要的东西使用内置字符串是不可能的,但使用自定义类可以让您做到。

关于python - 如何在python中获取property的setter方法的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52025193/

相关文章:

python matplotlib : label in histogram

Python如何在两个列表之间找到一个不完全相同的单词?

python - 为多个类定义方法

python - 格式化字符串的最 Pythonic 方式

python - 如何发送彩色短信?

python - 检查python中的多个条件

python - 将每日值合并到日内 DataFrame

python - 无法在图中添加图例

python - 在整个数据集上计算 TF-IDF 还是仅在训练数据上计算 TF-IDF?

python - 使用python从xml中提取具体数据