如何将多个相似属性应用于 class
How to apply multiple similar properties to a class
我目前正在学习 @property
装饰器。考虑下面的示例 class,名为 Rectangle
。它有 2 个属性,width
和 height
,它们都应该是严格的正整数。我使用 @property
装饰器强制执行此操作。
class Rectangle:
'''
A simple class to model a rectangle.
Parameters
----------
width : int
The width of the rectangle.
height : int
The height of the rectangle.
Returns
-------
None.
'''
#---INITIALIZATION---------------------------------------------------------
def __init__(self, width : int, height : int):
self.width = width
self.height = height
#---PROPERTIES-------------------------------------------------------------
@property
def width(self):
return self._width
@width.setter
def width(self, val : int):
if isinstance(val, int) and val > 0:
self._width = val
else:
raise ValueError('Width cannot be negative.')
@width.deleter
def width(self):
del self._width
@property
def height(self):
return self._height
@height.setter
def height(self, val : int):
if isinstance(val, int) and val > 0:
self._height = val
else:
raise ValueError('Height cannot be negative.')
@height.deleter
def height(self):
del self._height
#---SETTERS----------------------------------------------------------------
def set_width(self, val : int):
'''
Set the Rectangle width to any stricly positive integer value.
'''
self.width = val
def set_height(self, val):
'''
Set the Rectangle height to any stricly positive integer value.
'''
self.height = val
此代码运行良好。实例化 (Rectangle(-5,3)
)、直接赋值 (rect.width = -5
) 和 setter 方法 (rect.set_width(-5)
) 在维度不是严格正数时引发 ValueError
。但是,width
和height
这两个属性的修饰非常相似。 有没有一种干净的方法可以为具有相同条件(例如正整数)的不同属性生成 @property
装饰器模板?
奖励问题:我尝试创建一个 PositiveInteger
class。这确实会阻止实例化 (Rectangle(-5,3)
) 和 setter 方法 (rect.set_width(-5)
),但不正确的直接赋值 (rect.width = -5
) 仍然是可能的。 但为什么这不起作用?
class PositiveInteger:
'''
A simple class to decorate an attribute with an @property decorator to
enforce strictly positive values.
Parameters
----------
name : str
The name of the attribute.
value : int
The set value of the attribute.
Returns
-------
None.
'''
#---INITIALIZATION---------------------------------------------------------
def __init__(self, name : str, value : int):
self.name = name
self.value = value
#---PROPERTIES-------------------------------------------------------------
@property
def value(self):
return self._value
@value.setter
def value(self, val : int):
if isinstance(val, int) and val > 0:
self._value = val
else:
raise ValueError(f'{self.name.capitalize()} cannot be negative.')
@value.deleter
def value(self):
del self._value
#==============================================================================
class Rectangle:
'''
A simple class to model a rectangle.
Parameters
----------
width : int
The width of the rectangle.
height : int
The height of the rectangle.
Returns
-------
None.
'''
#---INITIALIZATION---------------------------------------------------------
def __init__(self, width : int, height : int):
self.width = PositiveInteger('width', width).value
self.height = PositiveInteger('height', height).value
#---SETTERS----------------------------------------------------------------
def set_width(self, val : int):
'''
Set the Rectangle width to any stricly positive integer value.
'''
self.width = PositiveInteger('width', val).value
def set_height(self, val):
'''
Set the Rectangle height to any stricly positive integer value.
'''
self.height = PositiveInteger('height', val).value
提前致谢!
P.S。我喜欢 Stack Overflow 的重新设计。
我自己的回答 经过多天的谷歌搜索,我在 Python documentation 中发现了描述符 classes。一旦在外部 class 中实例化,描述符 class 就会管理外部 class 属性的获取和设置。这似乎适用于实例化、直接赋值和 setter 方法。发生不需要的更改的唯一方法是访问属性的私有名称,例如 rect._height = -5
.
#==============================================================================
class PositiveIntegerDescriptor:
'''
A descriptor class to enforce an attribute to be a strictly positive integer.
Parameters
----------
name : str
The name of the attribute.
Returns
-------
None.
'''
#--INITIALIZATION----------------------------------------------------------
def __init__(self, name : str):
self.public_name = name
self.private_name = '_' + name
#--GETTERS AND SETTERS-----------------------------------------------------
def __get__(self, obj, objtype=None):
return getattr(obj, self.private_name)
def __set__(self, obj, new_value):
if isinstance(new_value, int) and new_value > 0:
setattr(obj, self.private_name, new_value)
else:
raise ValueError(f'{self.public_name.capitalize()} must be a strictly positive integer.')
#==============================================================================
class Rectangle:
'''
A simple class to model a rectangle.
Parameters
----------
width : int
The width of the rectangle.
height : int
The height of the rectangle.
Returns
-------
None.
'''
#---DESCRIPTORS------------------------------------------------------------
width = PositiveIntegerDescriptor('width')
height = PositiveIntegerDescriptor('height')
#---INITIALIZATION---------------------------------------------------------
def __init__(self, width : int, height : int):
self.width = width
self.height = height
#---SETTERS----------------------------------------------------------------
def set_width(self, value : int):
'''
Set the Rectangle width to any stricly positive integer value.
'''
self.width = value
def set_height(self, value):
'''
Set the Rectangle height to any stricly positive integer value.
'''
self.height = value
#==============================================================================
我目前正在学习 @property
装饰器。考虑下面的示例 class,名为 Rectangle
。它有 2 个属性,width
和 height
,它们都应该是严格的正整数。我使用 @property
装饰器强制执行此操作。
class Rectangle:
'''
A simple class to model a rectangle.
Parameters
----------
width : int
The width of the rectangle.
height : int
The height of the rectangle.
Returns
-------
None.
'''
#---INITIALIZATION---------------------------------------------------------
def __init__(self, width : int, height : int):
self.width = width
self.height = height
#---PROPERTIES-------------------------------------------------------------
@property
def width(self):
return self._width
@width.setter
def width(self, val : int):
if isinstance(val, int) and val > 0:
self._width = val
else:
raise ValueError('Width cannot be negative.')
@width.deleter
def width(self):
del self._width
@property
def height(self):
return self._height
@height.setter
def height(self, val : int):
if isinstance(val, int) and val > 0:
self._height = val
else:
raise ValueError('Height cannot be negative.')
@height.deleter
def height(self):
del self._height
#---SETTERS----------------------------------------------------------------
def set_width(self, val : int):
'''
Set the Rectangle width to any stricly positive integer value.
'''
self.width = val
def set_height(self, val):
'''
Set the Rectangle height to any stricly positive integer value.
'''
self.height = val
此代码运行良好。实例化 (Rectangle(-5,3)
)、直接赋值 (rect.width = -5
) 和 setter 方法 (rect.set_width(-5)
) 在维度不是严格正数时引发 ValueError
。但是,width
和height
这两个属性的修饰非常相似。 有没有一种干净的方法可以为具有相同条件(例如正整数)的不同属性生成 @property
装饰器模板?
奖励问题:我尝试创建一个 PositiveInteger
class。这确实会阻止实例化 (Rectangle(-5,3)
) 和 setter 方法 (rect.set_width(-5)
),但不正确的直接赋值 (rect.width = -5
) 仍然是可能的。 但为什么这不起作用?
class PositiveInteger:
'''
A simple class to decorate an attribute with an @property decorator to
enforce strictly positive values.
Parameters
----------
name : str
The name of the attribute.
value : int
The set value of the attribute.
Returns
-------
None.
'''
#---INITIALIZATION---------------------------------------------------------
def __init__(self, name : str, value : int):
self.name = name
self.value = value
#---PROPERTIES-------------------------------------------------------------
@property
def value(self):
return self._value
@value.setter
def value(self, val : int):
if isinstance(val, int) and val > 0:
self._value = val
else:
raise ValueError(f'{self.name.capitalize()} cannot be negative.')
@value.deleter
def value(self):
del self._value
#==============================================================================
class Rectangle:
'''
A simple class to model a rectangle.
Parameters
----------
width : int
The width of the rectangle.
height : int
The height of the rectangle.
Returns
-------
None.
'''
#---INITIALIZATION---------------------------------------------------------
def __init__(self, width : int, height : int):
self.width = PositiveInteger('width', width).value
self.height = PositiveInteger('height', height).value
#---SETTERS----------------------------------------------------------------
def set_width(self, val : int):
'''
Set the Rectangle width to any stricly positive integer value.
'''
self.width = PositiveInteger('width', val).value
def set_height(self, val):
'''
Set the Rectangle height to any stricly positive integer value.
'''
self.height = PositiveInteger('height', val).value
提前致谢! P.S。我喜欢 Stack Overflow 的重新设计。
我自己的回答 经过多天的谷歌搜索,我在 Python documentation 中发现了描述符 classes。一旦在外部 class 中实例化,描述符 class 就会管理外部 class 属性的获取和设置。这似乎适用于实例化、直接赋值和 setter 方法。发生不需要的更改的唯一方法是访问属性的私有名称,例如 rect._height = -5
.
#==============================================================================
class PositiveIntegerDescriptor:
'''
A descriptor class to enforce an attribute to be a strictly positive integer.
Parameters
----------
name : str
The name of the attribute.
Returns
-------
None.
'''
#--INITIALIZATION----------------------------------------------------------
def __init__(self, name : str):
self.public_name = name
self.private_name = '_' + name
#--GETTERS AND SETTERS-----------------------------------------------------
def __get__(self, obj, objtype=None):
return getattr(obj, self.private_name)
def __set__(self, obj, new_value):
if isinstance(new_value, int) and new_value > 0:
setattr(obj, self.private_name, new_value)
else:
raise ValueError(f'{self.public_name.capitalize()} must be a strictly positive integer.')
#==============================================================================
class Rectangle:
'''
A simple class to model a rectangle.
Parameters
----------
width : int
The width of the rectangle.
height : int
The height of the rectangle.
Returns
-------
None.
'''
#---DESCRIPTORS------------------------------------------------------------
width = PositiveIntegerDescriptor('width')
height = PositiveIntegerDescriptor('height')
#---INITIALIZATION---------------------------------------------------------
def __init__(self, width : int, height : int):
self.width = width
self.height = height
#---SETTERS----------------------------------------------------------------
def set_width(self, value : int):
'''
Set the Rectangle width to any stricly positive integer value.
'''
self.width = value
def set_height(self, value):
'''
Set the Rectangle height to any stricly positive integer value.
'''
self.height = value
#==============================================================================