简体   繁体   English

有没有办法让属性的 += 和 -= 调用实例的方法?

[英]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_knotremove_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_knotremove_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:那么有两种可能:

  1. Call the 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 variable myvector , and then it changes mycurve 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
  1. Modify in 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM