使用 property 和 setter 装饰器,我可以定义 getter 和 setter 函数。这对于基元来说很好,但是如何索引集合或 numpy 数组呢? 设置值似乎可以与索引一起使用,但 setter 函数不会被调用。否则,将执行最小示例中的打印函数。
class Data:
def __init__(self):
self._arr = [0, 1, 2]
@property
def arr(self):
return self._arr
@arr.setter
def arr(self, value):
print("new value set") # I want this to be executed
self._arr = value
data = Data()
print(data.arr) # prints [0, 1, 2]
data.arr[2] = 5
print(data.arr) # prints [0, 1, 5]
如果您只想对类实例的一个列表执行此操作,您可以通过使用类的 __set_item__
和
__get_item__
dunder 方法来以某种方式执行此操作:
class Data:
def __init__(self):
self._arr = [0, 1, 2]
@property
def arr(self):
return self._arr
@arr.setter
def arr(self, value):
print("new inner list set")
self._arr = value
def __setitem__(self, key, value):
print("new value set")
self._arr[key] = value
def __getitem__(self, key):
return self._arr[key]
data = Data()
print(data.arr)
data[2] = 5
print(data.arr)
data.arr = [42, 43]
print(data.arr)
输出:
[0, 1, 2]
new value set # by data[2] = 5 using __set_item__
[0, 1, 5]
new inner list set # by data.arr = [42, 43] using @arr.setter
[42, 43]
这仅适用于一个列表成员,因为
__set_item__
正在处理类实例本身,而不是类实例成员的列表。
您需要使用一个辅助类将索引/切片函数包装到该对象类型上。例如,这就是在 numpy 数组中使用切片时发生的情况。
(来源:受到this答案的启发)
class SubData():
def __init__(self, arr):
self._arr = arr.copy()
def __getitem__(self, index):
print("SubData getter")
return self._arr[index]
def __setitem__(self, index, value):
print("SubData setter")
self._arr[index] = value
def __str__(self):
return str(self._arr)
class Data():
def __init__(self, vals):
self._arr = SubData(vals)
@property
def arr(self):
print("Data getter")
return self._arr
@arr.setter
def arr(self, value):
print("Data setter")
self._arr = value
#--main--
>a = Data([1,2,3])
>a.arr[2]=5
Data getter
SubData setter
>print(a.arr)
Data getter
[1, 2, 5]
对于更复杂的行为,例如二维数组,您需要检查索引的实例(即,
a.arr[2,5
将元组传递给索引)。