有没有办法以编程方式创建非常相似的 class 属性?
Is there a way to programmatically create very similar class properties?
我做了一个简单的 class 来接受一个表示数组形状的元组,并将名称分配给最后三个维度(深度、高度、宽度)作为 class 属性。我有兴趣将这些属性设置为属性,以便实例形状的任何更改都将反映在这些属性中。这会造成我有重复代码的情况,如果我决定在将来分配更多维度名称或 setter / 删除器,情况会变得更糟。
这是我的(精简版)class:
class Shape():
"""A class to represent 4-dimension names of a shape tuple"""
def __init__(self, shape):
"""Shape instance is initialized with a shape tuple
Args:
shape (tuple): a tuple representing an array shape
"""
self.shape = shape
@property
def shape(self):
return self._shape
@shape.setter
def shape(self, value):
self._shape = value
# ndim is needed in case number of elements in shape is not equal to 3
@property
def ndim(self):
return len(self.shape)
# width, height, depth are similar
@property
def width(self):
"""Last dimension of shape"""
if self.ndim >= 1:
return self.shape[-1]
@property
def height(self):
"""Second last dimension of shape"""
if self.ndim >= 2:
return self.shape[-2]
@property
def depth(self):
"""Third last dimension of shape"""
if self.ndim >= 3:
return self.shape[-3]
实例化 class:
x = (4, 5)
shape1 = Shape(x)
print(shape1.shape)
print((shape1.depth, shape1.height, shape1.width))
(4, 5)
(None, 4, 5)
正在将形状属性设置为新值:
shape1.shape = (3, 2, 1)
print(shape1.shape)
print((shape1.depth, shape1.height, shape1.width))
(3, 2, 1)
(3, 2, 1)
所以我的 class 按预期工作,但是是否有更简洁的方法来在循环中设置多个相似的属性?我试图在 init 的循环中使用 setattr()。这适用于设置常规 class 属性,但我找不到用它设置属性的方法,这意味着属性将不再反映对实例形状的更新。
每个单独的 属性 都可以根据更通用的私有方法来实现。
class Shape:
def __init__(self, shape):
self.shape = shape
def _get_dim(self, i):
try:
return self.shape[i]
except IndexError:
return None
@property
def shape(self):
return self._shape
@shape.setter
def shape(self, value):
self._shape = value
@property
def ndim(self):
return len(self.shape)
width = property(lambda self: self._get_dim(0))
height = property(lambda self: self._get_dim(1))
depth = property(lambda self: self._get_dim(2))
您可能更喜欢使用 operator.methodcaller
而不是 lambda 表达式,例如width = property(methodcaller("_get_dim", 0))
您可以更进一步,定义您自己的自定义描述符来代替 property
。
class Dimension:
def __init__(self, n):
self.n = n
def __get__(self, obj, cls):
if obj is None:
return self
try:
return obj.shape[n]
except IndexError:
return None
class Shape:
width = Dimension(0)
height = Dimension(1)
depth = Dimension(2)
def __init__(self, shape):
self.shape = shape
@property
def shape(self):
return self._shape
@shape.setter
def shape(self, value):
self._shape = value
@property
def ndim(self):
return len(self.shape)
我做了一个简单的 class 来接受一个表示数组形状的元组,并将名称分配给最后三个维度(深度、高度、宽度)作为 class 属性。我有兴趣将这些属性设置为属性,以便实例形状的任何更改都将反映在这些属性中。这会造成我有重复代码的情况,如果我决定在将来分配更多维度名称或 setter / 删除器,情况会变得更糟。
这是我的(精简版)class:
class Shape():
"""A class to represent 4-dimension names of a shape tuple"""
def __init__(self, shape):
"""Shape instance is initialized with a shape tuple
Args:
shape (tuple): a tuple representing an array shape
"""
self.shape = shape
@property
def shape(self):
return self._shape
@shape.setter
def shape(self, value):
self._shape = value
# ndim is needed in case number of elements in shape is not equal to 3
@property
def ndim(self):
return len(self.shape)
# width, height, depth are similar
@property
def width(self):
"""Last dimension of shape"""
if self.ndim >= 1:
return self.shape[-1]
@property
def height(self):
"""Second last dimension of shape"""
if self.ndim >= 2:
return self.shape[-2]
@property
def depth(self):
"""Third last dimension of shape"""
if self.ndim >= 3:
return self.shape[-3]
实例化 class:
x = (4, 5)
shape1 = Shape(x)
print(shape1.shape)
print((shape1.depth, shape1.height, shape1.width))
(4, 5)
(None, 4, 5)
正在将形状属性设置为新值:
shape1.shape = (3, 2, 1)
print(shape1.shape)
print((shape1.depth, shape1.height, shape1.width))
(3, 2, 1)
(3, 2, 1)
所以我的 class 按预期工作,但是是否有更简洁的方法来在循环中设置多个相似的属性?我试图在 init 的循环中使用 setattr()。这适用于设置常规 class 属性,但我找不到用它设置属性的方法,这意味着属性将不再反映对实例形状的更新。
每个单独的 属性 都可以根据更通用的私有方法来实现。
class Shape:
def __init__(self, shape):
self.shape = shape
def _get_dim(self, i):
try:
return self.shape[i]
except IndexError:
return None
@property
def shape(self):
return self._shape
@shape.setter
def shape(self, value):
self._shape = value
@property
def ndim(self):
return len(self.shape)
width = property(lambda self: self._get_dim(0))
height = property(lambda self: self._get_dim(1))
depth = property(lambda self: self._get_dim(2))
您可能更喜欢使用 operator.methodcaller
而不是 lambda 表达式,例如width = property(methodcaller("_get_dim", 0))
您可以更进一步,定义您自己的自定义描述符来代替 property
。
class Dimension:
def __init__(self, n):
self.n = n
def __get__(self, obj, cls):
if obj is None:
return self
try:
return obj.shape[n]
except IndexError:
return None
class Shape:
width = Dimension(0)
height = Dimension(1)
depth = Dimension(2)
def __init__(self, shape):
self.shape = shape
@property
def shape(self):
return self._shape
@shape.setter
def shape(self, value):
self._shape = value
@property
def ndim(self):
return len(self.shape)