python - 使用 Descriptor 和 Decorator 检查类型属性:访问属性时“__get__() 接受 2 个位置参数,但给出了 3 个”
问题描述
目标
我尝试实现一个像类型检查功能一样的装饰器。我还没到那里,因为验证运行良好,但是当我尝试访问该属性时,我得到了错误:TypeError: __get__() takes 2 positional arguments but 3 were given
。
我正在使用 Python 3.9.7。
描述
# Descriptor definition
class PositiveNumber:
def __get__(self, obj):
return self.value
def __set__(self, obj, value):
if not isinstance(value, (int, float)):
raise TypeError('value must be a number')
if value < 0:
raise ValueError('Value cannot be negative.')
self.value = value
# Decorator definition
def positive_number(attr):
def decorator(cls):
setattr(cls, attr, PositiveNumber())
return cls
return decorator
# class that actually check for the right type
@positive_number('number')
class MyClass(object):
def __init__(self, value):
self.number = value
def main():
a = MyClass(3)
print(a.number)
if __name__ == '__main__':
main()
你看到解决这个问题的方法了吗?
解决方案
你签名错了 调用时__get__
,会传递 3 个参数(包括您是否使用它的类型):
class PositiveNumber:
def __get__(self, obj, objtype=None):
return self.value
# ...
另一件事是错误的:只有一个描述符实例,所以所有实例都MyClass
将共享该对象的value
属性!
a = MyClass(3)
b = MyClass(5)
a.number
# 5
因此,您最好将设置值与实例关联起来:
class PositiveNumber:
def __get__(self, obj, objtype=None):
return obj._value
def __set__(self, obj, value):
if not isinstance(value, (int, float)):
raise TypeError('value must be a number')
if value < 0:
raise ValueError('Value cannot be negative.')
obj._value = value
您还可以根据实际类上的字段名称使用更具体的属性名称:
class PositiveNumber:
def __set_name__(self, owner, name):
self.private_name = '_' + name # e.g. "_number"
def __get__(self, obj, objtype=None):
return getattr(obj, self.private_name)
def __set__(self, obj, value):
if not isinstance(value, (int, float)):
raise TypeError('value must be a number')
if value < 0:
raise ValueError('Value cannot be negative.')
setattr(obj, self.private_name, value)
set_name
仅当描述符在类创建时已经存在时才调用该方法。这意味着您不能setattr
在已经存在的类对象上动态设置它,但您必须创建一个新类!
def positive_number(attr):
def decorator(cls):
return type(cls.__name__, (cls,), {attr: PositiveNumber()})
return decorator
推荐阅读
- javascript - 如何从 Javascript 动态调用 Java 函数?
- javascript - 切换复选框在 Angular js 中不起作用,它只是一直在炫耀
- mysql - 简单查询运行缓慢
- bash - 使用 awk 将多行合并为单行记录,同时删除一些数据
- amazon-web-services - 卓:如何知道异步理解作业何时完成?
- ruby-on-rails - Rails 调查 - 如何显示当前问题的总数?
- javascript - 匹配正则表达式时更改文本颜色 - JavaScript
- python - Webscraping:使用字典中的 for 循环简化代码
- python-3.x - “DataFrame”对象在 Pandas 中没有属性“get_value”
- sql-server - 为什么 ADODB.connection 对象会吞下错误?