Python 的@属性 等同于 Processing 中的 class 声明?
Python's @property equivalent in class declaration in Processing?
在寒假回家期间,我将尝试使用 Processing 编程语言(Java 风格)制作一些很酷的东西。对于我的第一个项目,我想定义一个自定义 Line class 以使在线计算更容易。在 python 中,它将是这样的:
import numpy as np
class Line():
def __init__(self, x1, y1, x2, y2):
self.x1, self.x2 = x1, x2
self.y1, self.y2 = y1, y2
@property
def p1(self):
return np.array([self.x1, self.y1])
@property
def p2(self):
return np.array([self.x2, self.y2])
这样的话,如果x1, ..., y2改变了,相应的点向量也改变了。显然这个例子有点低效,但重点仍然存在。在javascript,我知道Object.defineProperty(obj, prop, descriptor)
,但不清楚
- 如何在处理中做到这一点
- 这是发挥作用的地方。定义 class 时的等效操作是什么?
编辑:澄清为什么 @property
特别有用:
假设我希望以两种方式表示直线,这两种方式都将由 Line 对象存储:
- 一个,普通版本:两个点,p1 和 p2,每个点由 x、y 坐标组成。
- 两个具有两个点 u 和 v 的参数化版本,使得 p1 = u 和 p2 = u + v,线段上的任何点由 u + t * v 给出,其中 t 是介于0 和 1。
如果 p2 改变,v 也会改变,反之亦然。更改 p1 将更改 u 和 v。一些数学在参数化版本方面更容易完成,而一些在普通版本方面更容易完成,所以我希望对任何属性所做的任何更改都正确更新其他属性,使 p1、p2 和 u、v 始终代表相同的行。
在 python 中,我可以修改 属性 的 setter 和 getter 方法来适当地解释所有这些,但我似乎无法确定在处理中执行此操作的一种方法。
如果您只使用常规的 Processing 对象和语法,您几乎可以自动获得它。
例如,您可以使用两个 PVector
实例来定义端点。
class Line{
PVector p1;
PVector p2;
public Line(float x1, float y1, float x2, float y2){
p1 = new PVector(x1, y1);
p2 = new PVector(x2, y2);
}
}
然后,如果您想更改这些端点之一,您可以直接访问 PVector
个实例:
Line myLine = new Line(0, 10, 25, 100);
println(myLine.p1.x + ", " myLine.p1.y);
myLine.p1.x = 750;
println(myLine.p1.x + ", " myLine.p1.y);
您还可以获得 PVector class 中已定义的所有数学内容。
您可以更好地 "protect" 您的 PVector
变量,方法是将它们设为最终变量或仅允许 Line
class 的用户通过设置器更改端点,然后访问PVector
个实例。
编辑:我会尽量在这里回答您的其他问题。
is public necessary?
这完全取决于您如何使用此 class、您希望其他人如何访问它等。您可以在 the Processing reference 中了解这一点,或者只是 google 类似于 "java access modifiers"。或者你可以试着把它拿出来,看看会发生什么。
what if I want both the vanilla definition of a line (x1, y1, x2, y2) and the parameterized (u1, u2, v1, v2, s.t. x1 = u1 and x2 = u1 + v1, etc) versions simultaneously? In this case, and importantly, if x2 is updated, so should v1 be updated.
我不太确定你在这里问什么。当你写下你的 class 时,你可以决定 你如何代表你的状态 以及 你如何让人们与该状态互动 。
例如,我上面的示例使用两个 PVector
实例来表示该行,它允许人们直接与它们交互以修改该行。但我可以添加一个函数,让他们将一条线定义为一个点、一个角度和一段距离。我只需要确保我计算出第二个点,这样我就可以存储我的状态。像这样:
class Line{
PVector p1;
PVector p2;
public Line(float x1, float y1, float x2, float y2){
p1 = new PVector(x1, y1);
p2 = new PVector(x2, y2);
}
public Line(PVector origin, float angle, float distance){
p1 = origin;
p2 = new PVector(origin.x + cos(angle)*distance, origin.y + sin(angle)*distance);
}
}
请注意,第二个构造函数允许用户以完全不同的方式指定一行,但我仍然将我的状态存储为两个 PVector
实例。如果您以后需要它们,您可以存储 angle
和 distance
值,并且您可以拥有允许用户修改它们的设置器 - 您只需要相应地更新您的 PVector
值。
在寒假回家期间,我将尝试使用 Processing 编程语言(Java 风格)制作一些很酷的东西。对于我的第一个项目,我想定义一个自定义 Line class 以使在线计算更容易。在 python 中,它将是这样的:
import numpy as np
class Line():
def __init__(self, x1, y1, x2, y2):
self.x1, self.x2 = x1, x2
self.y1, self.y2 = y1, y2
@property
def p1(self):
return np.array([self.x1, self.y1])
@property
def p2(self):
return np.array([self.x2, self.y2])
这样的话,如果x1, ..., y2改变了,相应的点向量也改变了。显然这个例子有点低效,但重点仍然存在。在javascript,我知道Object.defineProperty(obj, prop, descriptor)
,但不清楚
- 如何在处理中做到这一点
- 这是发挥作用的地方。定义 class 时的等效操作是什么?
编辑:澄清为什么 @property
特别有用:
假设我希望以两种方式表示直线,这两种方式都将由 Line 对象存储:
- 一个,普通版本:两个点,p1 和 p2,每个点由 x、y 坐标组成。
- 两个具有两个点 u 和 v 的参数化版本,使得 p1 = u 和 p2 = u + v,线段上的任何点由 u + t * v 给出,其中 t 是介于0 和 1。
如果 p2 改变,v 也会改变,反之亦然。更改 p1 将更改 u 和 v。一些数学在参数化版本方面更容易完成,而一些在普通版本方面更容易完成,所以我希望对任何属性所做的任何更改都正确更新其他属性,使 p1、p2 和 u、v 始终代表相同的行。
在 python 中,我可以修改 属性 的 setter 和 getter 方法来适当地解释所有这些,但我似乎无法确定在处理中执行此操作的一种方法。
如果您只使用常规的 Processing 对象和语法,您几乎可以自动获得它。
例如,您可以使用两个 PVector
实例来定义端点。
class Line{
PVector p1;
PVector p2;
public Line(float x1, float y1, float x2, float y2){
p1 = new PVector(x1, y1);
p2 = new PVector(x2, y2);
}
}
然后,如果您想更改这些端点之一,您可以直接访问 PVector
个实例:
Line myLine = new Line(0, 10, 25, 100);
println(myLine.p1.x + ", " myLine.p1.y);
myLine.p1.x = 750;
println(myLine.p1.x + ", " myLine.p1.y);
您还可以获得 PVector class 中已定义的所有数学内容。
您可以更好地 "protect" 您的 PVector
变量,方法是将它们设为最终变量或仅允许 Line
class 的用户通过设置器更改端点,然后访问PVector
个实例。
编辑:我会尽量在这里回答您的其他问题。
is public necessary?
这完全取决于您如何使用此 class、您希望其他人如何访问它等。您可以在 the Processing reference 中了解这一点,或者只是 google 类似于 "java access modifiers"。或者你可以试着把它拿出来,看看会发生什么。
what if I want both the vanilla definition of a line (x1, y1, x2, y2) and the parameterized (u1, u2, v1, v2, s.t. x1 = u1 and x2 = u1 + v1, etc) versions simultaneously? In this case, and importantly, if x2 is updated, so should v1 be updated.
我不太确定你在这里问什么。当你写下你的 class 时,你可以决定 你如何代表你的状态 以及 你如何让人们与该状态互动 。
例如,我上面的示例使用两个 PVector
实例来表示该行,它允许人们直接与它们交互以修改该行。但我可以添加一个函数,让他们将一条线定义为一个点、一个角度和一段距离。我只需要确保我计算出第二个点,这样我就可以存储我的状态。像这样:
class Line{
PVector p1;
PVector p2;
public Line(float x1, float y1, float x2, float y2){
p1 = new PVector(x1, y1);
p2 = new PVector(x2, y2);
}
public Line(PVector origin, float angle, float distance){
p1 = origin;
p2 = new PVector(origin.x + cos(angle)*distance, origin.y + sin(angle)*distance);
}
}
请注意,第二个构造函数允许用户以完全不同的方式指定一行,但我仍然将我的状态存储为两个 PVector
实例。如果您以后需要它们,您可以存储 angle
和 distance
值,并且您可以拥有允许用户修改它们的设置器 - 您只需要相应地更新您的 PVector
值。