我使用描述符来定义接口类的寄存器:
class Register(object):
def __init__(self, address, docstring="instance docstring"):
self.address = address
self.__doc__ = docstring
def __get__(self, obj, objtype):
return obj.read(self.address)
def __set__(self, obj, val):
return obj.write(self.address, val)
class Interface(object):
r = Register(0x00, docstring="the first register") 我希望ipython的用户能够执行以下操作之一:
i = Interface()
i.r? #should show the docstring "the first register"或
i = Interface()
i.r( #should show the docstring "the first register" when parentheses are opened但是,docstring总是来自obj.read返回的int对象,而不是指定的docstring。在这种情况下,有方法显示正确的docstring吗?
如果我不是使用描述符,而是手动定义它们,则当括号打开时,它可以工作:
class Interface(object):
@property
def r(self):
"""this docstring will be shown alternatively"""
return self.read(0x0)
@r.setter
def r(self,v):
"""this is the docstring that is shown"""
self.write(0x0,v)
i = Interface()
i.r( #the right docstring pops up here once i open the bracket如果setter没有定义docstring,则在打开括号时显示一个getter。
我是否可以通过在没有不合理开销的情况下使用描述符来获得相同的行为呢?
我的问题有点类似于这个问题,但没有给出令人满意的答案:在Python描述符中创建动态文档字符串
发布于 2022-03-29 18:50:22
有两个问题。首先,描述符API也适用于类。因此,当Ipython试图从类中获取描述符时,实例__get__逻辑将被调用,这恰好会导致AttributeError失败,因此描述符将被忽略。在您的示例中,如果试图从Interface获取属性,则会引发一个错误,因为它试图在实例上运行(在本例中为None ):
In [25]: Interface.r
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-25-dd7a6e721f7e> in <module>
----> 1 Interface.r
<ipython-input-24-7d19c1ba4fe6> in __get__(self, obj, objtype)
5
6 def __get__(self, obj, objtype):
----> 7 return obj.read(self.address)
8
9 def __set__(self, obj, val):
AttributeError: 'NoneType' object has no attribute 'read'第二个问题是,Ipython只在描述符是property (硬编码)的实例时才使用描述符进行帮助。这方面的逻辑是这里。
要修复第一个问题,如果描述符为obj传递None,则希望返回描述符本身:
def __get__(self, obj, objtype=None):
if obj is None:
return self
...要解决第二个问题,要么需要向ipython提交修补程序,要么需要从属性中提交子类(虽然有点麻烦,但要容易得多)。把它们放在一起:
class Register(property):
def __init__(self, address, docstring="instance docstring"):
self.address = address
self.__doc__ = docstring
def __get__(self, obj, objtype=None):
if obj is None:
return self
return obj.read(self.address)
def __set__(self, obj, val):
return obj.write(self.address, val)
class Interface(object):
r = Register(0x00, docstring="the first register")
i = Interface()然后在ipython中,您可以得到:
In [21]: i.r?
Type: Register
String form: <__main__.Register object at 0x1051203a0>
Docstring: the first registerhttps://stackoverflow.com/questions/37255109
复制相似问题