有没有一种方法可以通过编程方式创建非常相似的类属性



我制作了一个简单的类,用于接收表示数组形状的元组,并将名称分配给最后三个维度(深度、高度、宽度(作为类属性。我感兴趣的是将这些属性设置为属性,以便实例形状的任何更改都将反映在这些属性中。这就造成了代码重复的情况,如果我决定在未来分配更多的维度名称或setter/deleter,情况会变得更糟。

这是我的(精简版(课程:


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]

实例化类:

x = (4, 5)
shape1 = Shape(x)
print(shape1.shape)
print((shape1.depth, shape1.height, shape1.width))

(4,5(
(无,4,5(

将形状属性设置为新值:

shape1.shape = (3, 2, 1)
print(shape1.shape)
print((shape1.depth, shape1.height, shape1.width))

(3,2,1(
(3,2,4(

所以我的类按预期工作,但有没有一种更干净的方法可以在循环中设置多个类似的属性?我试图在init中的循环中使用setattr((。这适用于设置常规类属性,但我找不到用它设置属性的方法,这意味着属性将不再反映对实例形状的更新。

每个单独的属性都可以用更通用的私有方法来实现。

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)

相关内容

最新更新