【问题标题】:What does "exception raising placeholder" mean in the Descriptor HowTo Guide?描述符操作指南中的“异常引发占位符”是什么意思?
【发布时间】:2022-10-22 01:10:18
【问题描述】:

在 Python 的 Descriptor HowTo Guide 中有这一段(加粗):

描述符操作指南

Descriptor protocol

(...)

要创建只读数据描述符,请同时定义 __get__() 和 __set__(),并在调用时使用 __set__() 引发 AttributeError。定义 __set__() 方法异常引发占位符足以使其成为数据描述符。

我不确定表达式:"exception raising placeholder" 这里的确切含义(谷歌搜索“异常占位符”也无助于澄清表达式),因为 Google 上的唯一结果是来自“描述符操作指南”本身。

这是否意味着在描述符的__set__() 中引发任何异常?例外是否必须是AttributeError?还是有别的意思?

【问题讨论】:

    标签: python exception python-descriptors


    【解决方案1】:

    这意味着,如果你想要一个数据描述符,你所需要的只是它有一个 __set__ 方法——即使 __set__ 方法在调用时总是会引发异常,它仍然是一个数据描述符。

    这种“总是引发异常的方法”是文档中“引发异常的占位符”的意思。

    没有__set__ 方法的类是“非数据描述符”——主要变化是对于非数据描述符,实例是总是在检索属性时检查 - 即使该类中有(非数据)描述符,具有相同的名称,也会检索实例属性。因此,可以从类的特定实例中覆盖或“删除”方法:您只需为实例中的方法名称分配一些其他值,该值将用于代替原始方法。

    现在,如果描述符类确实有__set__方法,试图在实例上设置值总是会经过它,而实例值不是通过普通方式设置的。如果该方法引发异常,这会使描述符值不可变:在任何情况下都无法为其分配新值。 (当然,在类上分配它的名称将有效地删除整个描述符)

    有趣的是,Python propertyes 是总是数据描述符:属性对象本身确实有一个__set__ 方法,即使没有配置属性“setter”。确切的情况是,当尝试在此类属性中设置值时,将引发异常:没有设置器的 property 是包含 exception raising 方法的描述符的示例。

    一些sn-ps来演示要点:

    In [7]: class NonDataDescriptor:
       ...:     def __get__(self, inst, owner):
       ...:         return 23
       ...: 
    
    In [8]: class A:
       ...:     b = NonDataDescriptor()
       ...: 
    
    In [9]: c = A()
    
    In [10]: c.b
    Out[10]: 23
    
    In [11]: c.__dict__
    Out[11]: {}
    
    In [12]: c.b = 42
    
    In [13]: c.__dict__
    Out[13]: {'b': 42}
    
    In [14]: c.b
    Out[14]: 42
    
    In [15]: # descriptor is superseeded by value attributed to the instance
    
    In [16]: A().b   # in a new instance, the descriptor works as new
    Out[16]: 23
    
    In [19]: class ImutableDataDescriptor:
        ...:     def __get__(self, inst, owner):
        ...:         return 55
        ...:     def __set__(self, inst, value):
        ...:         # Look! An exception raising placeholder!!
        ...:         raise NotImplementedError()  # or whatever exception
        ...: 
    
    In [20]: class D:
        ...:     e = ImutableDataDescriptor()
        ...: 
    
    In [21]: f = D()
    
    In [22]: f.e
    Out[22]: 55
    
    In [23]: f.e = 3125
    ---------------------------------------------------------------------------
    NotImplementedError                       Traceback (most recent call last)
    Cell In [23], line 1
    ----> 1 f.e = 3125
    
    Cell In [19], line 6, in ImutableDataDescriptor.__set__(self, inst, value)
          4 def __set__(self, inst, value):
          5     # Look! An exception raising placeholder!!
    ----> 6     raise NotImplementedError()
    
    NotImplementedError: 
    
    In [24]: f.__dict__
    Out[24]: {}
    
    In [26]: class G:  
        ...:     # ordinary properties with no setters work as data-descriptors
        ...:     @property
        ...:     def h(self):
        ...:         return 17
        ...: 
    
    In [27]: i = G()
    
    In [28]: i.h
    Out[28]: 17
    
    In [29]: i.h = 23
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    Cell In [29], line 1
    ----> 1 i.h = 23
    
    AttributeError: property 'h' of 'G' object has no setter
    
    

    【讨论】:

      猜你喜欢
      • 2013-03-20
      • 2015-11-22
      • 2022-06-25
      • 2014-08-14
      • 2010-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多