我有一个来自库(numpy.ndarray)的对象,我在其中将__iadd__方法替换为自定义方法。 如果我调用object .__ iadd __(x),它会按预期工作。但是,object + = x似乎调用旧的(未取代的)方法。 我想防止在特定情况下发生numpy上的溢出,所以我为此创建了一个上下文管理器。这是(仍然很粗糙)代码:
class NumpyOverflowPreventer( object ):
inverse_operator= { '__iadd__':'__sub__', '__isub__':'__add__', '__imul__': '__div__', '__idiv__':'__mul__'}
def _operate( self, b, forward_operator ):
assert type(b) in (int, float)
reverse_operator= NumpyOverflowPreventer.inverse_operator[forward_operator]
uro= getattr(self.upper_range, reverse_operator)
lro= getattr(self.lower_range, reverse_operator)
afo= self.originals[ forward_operator ]
overflows= self.matrix > uro( b )
underflows= self.matrix < lro( b )
afo( b )
self.matrix[overflows]= self.upper_range
self.matrix[underflows]= self.lower_range
def __init__( self, matrix ):
m= matrix
assert m.dtype==np.uint8
self.matrix= m
self.lower_range= float(0)
self.upper_range= float(2**8-1)
def __enter__( self ):
import functools
self.originals={}
for op in NumpyOverflowPreventer.inverse_operator.keys():
self.originals[ op ] = getattr( self.matrix, op )
setattr( self.matrix, op, functools.partial(self._operate, forward_operator=op))
def __exit__( self, type, value, tb ):
for op in NumpyOverflowPreventer.inverse_operator.keys():
setattr( self.matrix, op, self.originals[ op ] )
运行这个:
a= np.matrix(255, dtype= np.uint8)
b= np.matrix(255, dtype= np.uint8)
with NumpyOverflowPreventer(a):
a+=1
with NumpyOverflowPreventer(b):
b.__iadd__(1)
print a,b
返回:
[[0]] [[255]]
答案 0 :(得分:2)
您看到的问题是实例上没有查找特殊的内置方法。它们在matrix
类型上查找。因此,在实例上替换它们不会导致它们间接使用。
实现目标的一种方法是使NumpyOverflowPreventer
成为您要解决的操作的包装器......
import numpy as np
import sys
class NumpyOverflowPreventer(object):
inverse_operator= {
'__iadd__': '__sub__',
'__isub__': '__add__',
'__imul__': '__div__',
'__idiv__': '__mul__'
}
def __init__(self, matrix):
m = matrix
assert m.dtype==np.uint8
self.matrix = m
self.lower_range = float(0)
self.upper_range = float(2**8-1)
def __iadd__(self, v):
# dynamic way to get the name "__iadd__"
self._operate(v, sys._getframe().f_code.co_name)
return self
def _operate(self, b, forward_operator):
assert type(b) in (int, float)
reverse_operator = self.inverse_operator[forward_operator]
uro= getattr(self.upper_range, reverse_operator)
lro= getattr(self.lower_range, reverse_operator)
afo= getattr(self.matrix, forward_operator)
overflows= self.matrix > uro( b )
underflows= self.matrix < lro( b )
afo( b )
self.matrix[overflows]= self.upper_range
self.matrix[underflows]= self.lower_range
我这里只定义了__iadd__
,我相信你可以用一些元类/装饰器动作动态地完成它们......但我保持简单。
用法:
a = np.matrix(255, dtype= np.uint8)
b = np.matrix(255, dtype= np.uint8)
p = NumpyOverflowPreventer(a)
p+=1
p = NumpyOverflowPreventer(b)
p.__iadd__(1)
print a,b
# [[255]] [[255]]
答案 1 :(得分:0)
如果有人对溢出问题感兴趣,并且记录了jdi和kindall的专业知识,那么运算符似乎必须是类方法 - 因此,动态方法生成需要自定义类。 &#39;我已经到达了以下工作原型(+ =, - =,* =。/ =)
class OverflowPreventer( object ):
'''A context manager that exposes a numpy array preventing simple operations from overflowing.
Example:
array= numpy.array( [255], dtype=numpy.uint8 )
with OverflowPreventer( array ) as prevented:
prevented+=1
print array'''
inverse_operator= { '__iadd__':'__sub__', '__isub__':'__add__', '__imul__': '__div__', '__idiv__':'__mul__'}
bypass_operators=['__str__', '__repr__', '__getitem__']
def __init__( self, matrix ):
class CustomWrapper( object ):
def __init__(self, matrix):
assert matrix.dtype==numpy.uint8
self.overflow_matrix= matrix
self.overflow_lower_range= float(0)
self.overflow_upper_range= float(2**8-1)
for op in OverflowPreventer.bypass_operators:
setattr(CustomWrapper, op, getattr(self.overflow_matrix, op))
def _overflow_operator( self, b, forward_operator):
m, lr, ur= self.overflow_matrix, self.overflow_lower_range, self.overflow_upper_range
assert type(b) in (int, float)
reverse_operator= OverflowPreventer.inverse_operator[forward_operator]
uro= getattr( ur, reverse_operator)
lro= getattr( lr, reverse_operator)
afo= getattr( m, forward_operator )
overflows= m > uro( b )
underflows= m < lro( b )
afo( b )
m[overflows]= ur
m[underflows]= lr
return self
def __getattr__(self, attr):
if hasattr(self.wrapped, attr):
return getattr(self.wrapped,attr)
else:
raise AttributeError
self.wrapper= CustomWrapper(matrix)
import functools
for op in OverflowPreventer.inverse_operator.keys():
setattr( CustomWrapper, op, functools.partial(self.wrapper._overflow_operator, forward_operator=op))
def __enter__( self ):
return self.wrapper
def __exit__( self, type, value, tb ):
pass