我可以为 python 3 中的描述符定义一个添加方法吗?
Can I define an add method for a descriptor in python 3?
我在这里引用了 python 文档,以了解如何在 python 中创建一个 class 属性 来控制 getter 和 setter 方法。
https://docs.python.org/3/howto/descriptor.html#id6
我使用以下代码创建了描述符 属性 class:
class PropNumberString(object):
def __init__(self, initval=None, name='var_int'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print("in getter")
return self.val
def __set__(self, obj, val):
print("in setter")
self.val = int(val)
def __add__(self, val):
print("adding")
print("val to add: ", val)
self.val = int(self.val) + int(val)
return self
def __radd__(self, val):
return self.__add__(val)
class ConnectionTemplate(object):
tid = PropNumberString(0, "ID")
我也尝试定义一个 add 方法,打算它总是添加一个整数,即使提供了一个字符串。这不行,好像调用了“__get__”然后调用了返回整数的add方法,而不是我的add方法。
这里有一个测试来证明:
my_template = ConnectionTemplate()
print("Getting value")
print(my_template.tid)
print("Updating value")
my_template.tid = 100
print("Doing add")
my_template.tid = my_template.tid + "1"
print(my_template.tid)
print("type: ", type(my_template.tid))
输出:
Getting value
in getter
0
Updating value
in setter
Doing add
in getter
Traceback (most recent call last):
File "connection_template.py", line 53, in <module>
my_template.tid = my_template.tid + "1"
TypeError: unsupported operand type(s) for +: 'int' and 'str'
有什么好的解决办法吗?
编辑:
这就是我最终所做的,其中包含了 Alex Hall
提供的答案
class StrInt(int):
def __add__(self, val):
return StrInt(super().__add__(int(val)))
__radd__ = __add__
class PropNumberString(object):
def __init__(self, val=None, name='var_name'):
self.val = StrInt(val)
self.name = name
def __get__(self, obj, objtype):
return self.val
def __set__(self, obj, val):
self.val = StrInt(val)
class ConnectionTemplate(object):
tid_field = "ID"
def __init__(self, tid=0):
self.tid = PropNumberString(tid, self.ansa_tid_field)
def __getattribute__(self, key):
# see https://docs.python.org/3/howto/descriptor.html#id5
"Emulate type_getattro() in Objects/typeobject.c"
attrib = object.__getattribute__(self, key)
if hasattr(attrib, '__get__'):
return attrib.__get__(None, self)
return attrib
def __setattr__(self, key, val):
try:
attrib = object.__getattribute__(self, key)
except AttributeError:
self.__dict__[key] = val
return
if hasattr(attrib, '__set__'):
attrib.__set__(None, val)
return
self.__dict__[key] = val
注意:
我使用自定义描述符而不是 属性 装饰器的动机是我希望我的属性能够包含自定义元数据,即 json 转储的键值。
您不需要为此定义自定义描述符。您只需要 tid
到 return 一个 class 即可添加您想要的方式。最好在设置而不是获取时进行转换。这是一个实现:
class MyInt(int):
def __add__(self, val):
return MyInt(super().__add__(int(val)))
__radd__ = __add__
class ConnectionTemplate(object):
def __init__(self):
self._tid = 0
@property
def tid(self):
return self._tid
@tid.setter
def tid(self, val):
self._tid = MyInt(val)
我在这里引用了 python 文档,以了解如何在 python 中创建一个 class 属性 来控制 getter 和 setter 方法。 https://docs.python.org/3/howto/descriptor.html#id6
我使用以下代码创建了描述符 属性 class:
class PropNumberString(object):
def __init__(self, initval=None, name='var_int'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print("in getter")
return self.val
def __set__(self, obj, val):
print("in setter")
self.val = int(val)
def __add__(self, val):
print("adding")
print("val to add: ", val)
self.val = int(self.val) + int(val)
return self
def __radd__(self, val):
return self.__add__(val)
class ConnectionTemplate(object):
tid = PropNumberString(0, "ID")
我也尝试定义一个 add 方法,打算它总是添加一个整数,即使提供了一个字符串。这不行,好像调用了“__get__”然后调用了返回整数的add方法,而不是我的add方法。
这里有一个测试来证明:
my_template = ConnectionTemplate()
print("Getting value")
print(my_template.tid)
print("Updating value")
my_template.tid = 100
print("Doing add")
my_template.tid = my_template.tid + "1"
print(my_template.tid)
print("type: ", type(my_template.tid))
输出:
Getting value
in getter
0
Updating value
in setter
Doing add
in getter
Traceback (most recent call last):
File "connection_template.py", line 53, in <module>
my_template.tid = my_template.tid + "1"
TypeError: unsupported operand type(s) for +: 'int' and 'str'
有什么好的解决办法吗?
编辑: 这就是我最终所做的,其中包含了 Alex Hall
提供的答案class StrInt(int):
def __add__(self, val):
return StrInt(super().__add__(int(val)))
__radd__ = __add__
class PropNumberString(object):
def __init__(self, val=None, name='var_name'):
self.val = StrInt(val)
self.name = name
def __get__(self, obj, objtype):
return self.val
def __set__(self, obj, val):
self.val = StrInt(val)
class ConnectionTemplate(object):
tid_field = "ID"
def __init__(self, tid=0):
self.tid = PropNumberString(tid, self.ansa_tid_field)
def __getattribute__(self, key):
# see https://docs.python.org/3/howto/descriptor.html#id5
"Emulate type_getattro() in Objects/typeobject.c"
attrib = object.__getattribute__(self, key)
if hasattr(attrib, '__get__'):
return attrib.__get__(None, self)
return attrib
def __setattr__(self, key, val):
try:
attrib = object.__getattribute__(self, key)
except AttributeError:
self.__dict__[key] = val
return
if hasattr(attrib, '__set__'):
attrib.__set__(None, val)
return
self.__dict__[key] = val
注意: 我使用自定义描述符而不是 属性 装饰器的动机是我希望我的属性能够包含自定义元数据,即 json 转储的键值。
您不需要为此定义自定义描述符。您只需要 tid
到 return 一个 class 即可添加您想要的方式。最好在设置而不是获取时进行转换。这是一个实现:
class MyInt(int):
def __add__(self, val):
return MyInt(super().__add__(int(val)))
__radd__ = __add__
class ConnectionTemplate(object):
def __init__(self):
self._tid = 0
@property
def tid(self):
return self._tid
@tid.setter
def tid(self, val):
self._tid = MyInt(val)