调用super().view()时子类dtype setter触发的原因及解决方法
问题解析与解决方案
触发子类dtype setter的原因
调用super().view(np.uint8)时,numpy内部在生成新视图数组的过程中,会自动设置数组的dtype属性。由于你的子类myarray覆盖了dtype的setter方法,而view返回的新对象仍然是myarray类型(view默认保留原数组的类型),所以numpy内部设置dtype的操作会触发你自定义的setter逻辑。
解决方法
方法一:避免覆盖numpy原生dtype属性
numpy的ndarray本身已经内置了dtype属性,强行覆盖会干扰其内部逻辑。建议使用自定义属性名来实现你的需求:
import numpy as np class myarray(np.ndarray): _custom_dtype = None def __new__(cls, in_data, dtype): obj = np.array(in_data, dtype).view(cls) obj._custom_dtype = dtype return obj def view(self, dtype = None): if dtype is None: return self else: return super().view(np.uint8) @property def custom_dtype(self): return self._custom_dtype @custom_dtype.setter def custom_dtype(self, value): print("Setter for custom_dtype in the child class is called!!") self._custom_dtype = value a = myarray([1, 2, 3, 4], dtype = np.uint16) b = a.view(dtype = np.uint8) print(b)
方法二:让view返回原生numpy数组
修改view方法,使其返回原生np.ndarray实例而非子类对象,这样就不会触发子类的setter:
def view(self, dtype = None): if dtype is None: return self else: # 先转成原生ndarray再生成视图 return super().view(np.ndarray).view(np.uint8)
方法三:在setter中过滤内部调用(不推荐)
如果必须保留dtype属性的覆盖,可以在setter中判断是否为numpy内部操作,但这种方法依赖numpy内部实现,后续版本可能失效:
import inspect import numpy as np class myarray(np.ndarray): __dtype = None def __new__(cls, in_data, dtype): obj = np.array(in_data, dtype).view(cls) return obj def view(self, dtype = None): if dtype is None: return self else: return super().view(np.uint8) @property def dtype(self): return self.__dtype if self.__dtype is not None else super().dtype @dtype.setter def dtype(self, value): # 检查调用栈,跳过numpy内部的调用 caller_frame = inspect.currentframe().f_back caller_module = caller_frame.f_globals.get('__name__', '') if not caller_module.startswith('numpy'): print("Setter for dtype in the child class is called!!") self.__dtype = value
内容的提问来源于stack exchange,提问作者MrAliB
相关产品推荐
相关产品推荐

