【问题标题】:How Can a function act like a descriptor?函数如何像描述符一样工作?
【发布时间】:2023-04-06 16:35:02
【问题描述】:
def typed_property(name, expected_type):
    storage_name = '_' + name

    @property
    def prop(self):
        return getattr(self, storage_name)

    @prop.setter
    def prop(self, value):
        if not isinstance(value, expected_type):
            raise TypeError('{} must be a {}'.format(name, expected_type))
        setattr(self, storage_name, value)
    return prop


class Person:
    name = typed_property('name', str)
    age = typed_property('age', int)
    def __init__(self, name, age):
        self.name = name
        self.age = age

函数 typed_property() 就像一个描述符。为什么执行这行代码时会调用prop() (name = typed_property('name', str))?

【问题讨论】:

    标签: python descriptor


    【解决方案1】:

    我不知道您所说的“描述符”是什么意思。 typed_property 允许属性调用函数进行额外处理。 prop() 在执行您提到的行时不会被调用。它在执行self.name = name 时被调用。 @prop.setter 使得对象可以响应这样的属性调用。

    【讨论】:

      【解决方案2】:

      当您调用typed_property 来设置类属性nameage 的值时,您实际上是在将它们定义为用于访问实例值self.nameself.age 的方法。为简单起见,这与以下省略年龄相同:

      class Person:
          def __init__(self, name):
              self.name = name
      
          @property
          def name(self):
              print("=== ACESSING")
              return self.name
      
          @name.setter
          def name(self, name):
              print("=== MUTATING")
              self.name = name
      
      

      这将name(self) 方法标记为self.name 的访问器,并将name(self, val) 标记为突变器。每当您尝试更改(变异)其分配属性的值时,都会调用 mutator,在本例中为 self.name。这包括当您在 __init__ 方法中调用它时。但是,使用上面定义的类将导致无限递归,因为我是从 mutator 内部调用 mutator。所以 "=== MUTATING" 会以递归错误结尾。所以需要做一个小调整:

      class Person:
          def __init__(self, name):
              self._name = name
      
          @property
          def name(self):
              print("=== ACCESSING")
              return self._name
      
          @name.setter
          def name(self, val):
              print("=== MUTATING")
              self._name = val
      

      现在基础属性名称为_name 而不是name,mutator 将设置_name 的值而不是为name 设置它并无限循环到自身。例如,使用上面定义的类:

      >>> p = Person("joshmeranda")
      >>> p.name
      === ACCESSING
      "joshmeranda"
      

      【讨论】:

        猜你喜欢
        • 2023-03-09
        • 1970-01-01
        • 2018-05-31
        • 2011-10-28
        • 1970-01-01
        • 2020-04-04
        • 2017-10-31
        • 2018-06-08
        相关资源
        最近更新 更多