[英]Is there a way to += and -= of an attribute call a instance's method?
Question: Is there a way to ( +=
and -=
) call ( insert_knot
and remove_knot
) in the class bellow?问题:有没有办法在下面的 class 中调用( +=
和-=
)( insert_knot
和remove_knot
)?
EDIT: It's not duplicated from this question , cause I'm changing an attribute of the class (summing and subtracting), not the instance by itself.编辑:它不是从这个问题中复制的,因为我正在更改 class 的属性(求和和减法),而不是实例本身。 I mean, I sum/subtract an attribute and a method of the instance should be called.我的意思是,我对属性求和/减去,应该调用实例的方法。
class SplineCurve:
def __init__(self, knot_vector: Tuple[float]):
self.knot_vector = knot_vector
@property
def degree(self) -> int:
return self.__degree
@property
def knot_vector(self) -> Tuple[float]:
return tuple(self.__knot_vector)
@degree.setter
def degree(self, new_value: int):
if new_value == self.degree:
return
if new_value > self.degree:
self.increase_degree(new_value - self.degree)
else:
self.decrease_degree(self.degree - new_value)
self.__degree = new_value
@knot_vector.setter
def knot_vector(self, new_value: Tuple[float]):
new_value = list(new_value)
new_value.sort() # Shouldn't be here, only in 'insert_knot'
self.__knot_vector = tuple(new_value)
def increase_degree(self, times: int):
self.compute_ctrl_points()
def decrease_degree(self, times: int):
self.compute_ctrl_points()
def insert_knot(self, knots: Tuple[float]):
print(f"Inserting knots {knots}")
new_knot_vector = list(self.knot_vector)
for knot in knots:
new_knot_vector += [knot]
new_knot_vector.sort()
self.knot_vector = new_knot_vector
self.compute_ctrl_points()
def remove_knot(self, knots: Tuple[float]):
print(f"Removing knots {knots}")
new_knot_vector = list(self.knot_vector)
for knot in knots:
new_knot_vector.remove(knot)
self.knot_vector = new_knot_vector
self.compute_ctrl_points()
def compute_ctrl_points(self):
print("I must be called on insertion and remotion")
Then I want to the user do it:然后我想让用户这样做:
mycurve = SplineCurve([0, 0, 1, 1])
print(mycurve.knot_vector) # (0, 0, 1, 1)
mycurve.knot_vector += (0.5, 0.5) # This line should called as 'mycurve.insert_knot((0.5, 0.5))'
print(mycurve.knot_vector) # (0, 0, 0.5, 0.5, 1, 1)
mycurve.knot_vector -= (0.5, 1) # This line should called as 'mycurve.remove_knot((0.5, 1))'
print(mycurve.knot_vector) # (0, 0, 0.5, 1)
For inserting knot, the printed value is correct, but the function insert_knot
(and Inserting knots...
is not printed).对于插入结,打印的值是正确的,但 function insert_knot
(和Inserting knots...
未打印)。
But for -=
gives the error TypeError: unsupported operand type(s) for -=: 'tuple' and 'tuple'
, which is normal, cause it's like但是对于-=
给出错误TypeError: unsupported operand type(s) for -=: 'tuple' and 'tuple'
,这是正常的,因为它就像
temp_value = mycurve.knot_vector - (0.5, 1) # Error here
mycurve.knot_vector = temp_value # Setter is only called here
Calling the argument on insert_knot
and remove_knot
should allow also:在insert_knot
和remove_knot
上调用参数也应该允许:
mycurve.knot_vector += numpy.array([0.3, 0.7])
mycurve.knot_vector += [0.4, 0.9]
The solution as proposed @interjay is to create a new class object that can sum with an iterable. @interjay 提出的解决方案是创建一个新的 class object ,它可以与一个迭代相加。
Then there's two possibilities:那么有两种可能:
curve.insert_knot
on __iadd__
and curve.remove_knot
on __isub__
using indirect reference, and then lose the curve's reference.使用间接引用调用curve.insert_knot
上的__iadd__
和curve.remove_knot
上的__isub__
,然后丢失曲线的引用。 We can return None
and curve.knot_vector setter
does nothing.我们可以返回None
并且curve.knot_vector setter
什么都不做。class KnotVector(Tuple): def __new__(cls, curve, args: tuple[float]): self = super(KnotVector, cls).__new__(cls, tuple(args)) self._curve = curve return self def __iadd__(self, knots: tuple[float]): if self._curve is not None: self._curve.insert_knot(knots) self._curve = None else: return tuple(self) + knots def __isub__(self, knots: tuple[float]): if self._curve is not None: self._curve.remove_knot(knots) self._curve = None else: return tuple(self) + knots class SplineCurve: ... @property def knot_vector(self) -> KnotVector: return KnotVector(self, tuple(self._knot_vector)) @knot_vector.setter def knot_vector(self, new_knot_vector: Tuple[float]): if new_value is None: return self._knot_vector = tuple(new_knot_vector)...
A problem that can happen is assigning
knot_vector
into a variablemyvector
, and then it changesmycurve
without noticing.可能发生的一个问题是将knot_vector
分配给变量myvector
,然后它会在不注意的情况下更改mycurve
。mycurve = SplineCurve([0, 0, 1, 1]) myvector = mycurve.knot_vector #... after many instructions myvector += (0.5, 0.5) # This will change mycurve
KnotVector
class to add and remove, and give the information to mycurve
through knot_vector setter
, the same way that happens for degree
:在KnotVector
class 中修改以添加和删除,并通过knot_vector setter
将信息提供给mycurve
,与degree
的方式相同:class KnotVector(Tuple): def __new__(cls, args: tuple[float]): return super(KnotVector, cls).__new__(cls, tuple(args)) def __iadd__(self, knots: tuple[float]): new_knot_vector = list(self) for knot in knots: new_knot_vector += [knot] new_knot_vector.sort() return tuple(new_knot_vector) def __isub__(self, knots: tuple[float]): new_knot_vector = list(self) for knot in knots: new_knot_vector.remove(knot) return tuple(new_knot_vector) class SplineCurve: ... @property def knot_vector(self) -> KnotVector: return KnotVector(self._knot_vector) @knot_vector.setter def knot_vector(self, new_knot_vector: Tuple[float]): if self._knot_vector == new_knot_vector: return if self.new_knots_inserted(new_knot_vector): self.insert_knot(self.get_new_knots(new_knot_vector)) else: self.remove_knot(self.get_removed_knots(new_knot_vector))...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.