使用描述符和装饰器检查类型属性:访问属性时“__get__() 接受 2 个位置参数,但给出了 3 个”
Check a type attribute with a Descriptor and a Decorator : "__get__() takes 2 positional arguments but 3 were given" when accessing the attribute
目标
我尝试实现一个可以充当类型检查功能的装饰器。我还没有到那里,因为验证工作正常,但是当我尝试访问该属性时,我收到错误消息: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:
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
方法只有在描述符在 class 创建时已经存在时才会被调用。这意味着您不能在已经存在的 class 对象上使用 setattr
动态设置它,但您必须创建一个新的 class!
def positive_number(attr):
def decorator(cls):
return type(cls.__name__, (cls,), {attr: PositiveNumber()})
return decorator
目标
我尝试实现一个可以充当类型检查功能的装饰器。我还没有到那里,因为验证工作正常,但是当我尝试访问该属性时,我收到错误消息: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:
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
方法只有在描述符在 class 创建时已经存在时才会被调用。这意味着您不能在已经存在的 class 对象上使用 setattr
动态设置它,但您必须创建一个新的 class!
def positive_number(attr):
def decorator(cls):
return type(cls.__name__, (cls,), {attr: PositiveNumber()})
return decorator