我在Python中有这个功能:
def Rotate_Vector(vector, axis, direction):
其中 vector 是3个元素的元组(每个元素代表笛卡尔坐标轴上矢量的三个坐标x,y,z),轴是坐标轴,方向是表示顺时针或逆时针运动的整数。
我希望在我的函数中控制输入参数是否正确:
我想知道在函数中执行这些控件(类型,值和元素数量)的正确方法。
编辑:
轴可能是6个可能的情况:(1,0,0)( - 1,0,0)(0,1,0)(0,-1,0)(0, 0,1)(0,0,-1)
答案 0 :(得分:3)
简短的回答是:不要。 Python是鸭子类型,所以只需要做你需要的,如果它不起作用,那么它就会出错。
例如,如果将向量限制为长度为3元组,那么传入列表的人呢?如果它做同样的工作,为什么对你传递的内容很重要?
如果你真的觉得自己需要,那么就这样做:
if direction not in {1, -1}:
raise ValueError("direction must be +1 or -1")
if not len(vector) == 3:
raise ValueError("vector must contain 3 values")
等...
然而,这违反了Python 请求宽恕而非许可的原则。
我还要注意,这里更好的选择是避免使用魔术数字。例如,添加Vector.FORWARD = +1
和Vector.BACKWARD = -1
,然后告诉人们将这些传递到方向。这仍然具有灵活性,但可以为人们指导使用方向。同样,您可以为矢量提供namedtuples
,以便在构建它们时提供指导。
值得注意的是PEP-8建议lowercase_with_underscores
使用函数名称,因此Rotate_Vector()
不是一个特别好的函数名,除非你被项目中的现有约定强迫。
答案 1 :(得分:2)
我会避免检查用户发送的容器类型。正如其他回答者所说,这会对代码造成无用的限制,从而阻止代码重新使用。从接口的角度来考虑它。只要参数符合接口,代码就应该对它们起作用并产生所需的结果。
此逻辑不适用于您希望强加的两个特定约束。具体来说,您希望axis
变量的条目位于{1, 0, -1}
,并且您希望方向变量位于{1, -1}
。
这些是有效的约束。我会像这样实现它们:
valid_axis_entries = set((1,0, -1))
valid_direction_values = set((1, -1))
def rotate_vector(vec, axis, direction):
if not all(entry in valid_axis_entries for entry in axis):
raise SomeErrorCondition
if direction not in valid_direction_values:
raise SomeOtherErrorCondition
我遵循的一般规则是允许任何有意义的输入和raise
在任何无意义的输入上出错。任何序列对于矢量都有意义,但是,根据您的算法,没有任何序列值对您的旋转轴有意义,itertools.islice
当然不是方向的有效输入。检测您知道的条件会导致算法失败并引发有用的错误消息,这对于您的代码用户来说是体贴的,因为它们允许他们发送任何有意义的内容。
另外,我建议您将方向参数作为命名变量存储为大写,并鼓励用户发送而不是依赖于魔术常量。
答案 2 :(得分:1)
如前所述,python是鸭子类型,因此您只需按照通常的方式执行操作,并期望用户处理所引发的任何异常。
最好只对单元进行单元测试,确保所有内容都能使用有效的数字,从而提高您对某些工作的信心,并让您更轻松地缩小可能的错误位置。
如果你真的想检查类型,你可以使用对象类型的断言(例如isinstance(direction, int)
)来进行调试,但这实际上只是“穷人的单元测试”。
使用python的原则(请求宽恕,而不是权限,显式比隐式更好),我会做这样的事情:
import math
def rotate_vector(vector, axis, direction):
try:
x, y, z = vector
except TypeError:
raise TypeError("Invalid vector {0}".format(vector))
valid_axes = {(1,0,0), (-1,0,0), (0,1,0), (0,-1,0), (0,0,1), (0,0,-1)}
if not axis in valid_axes:
raise ValueError("Invalid axis {0}".format(axis))
try:
ax, ay, az = axis
except TypeError:
raise TypeError("Invalid axis {0}".format(axis))
# do math to rotate the vector
# rotated = ...
try:
# You really only need the sign of the direction
return math.copysign(rotated, direction)
# or:
return rotated * math.copysign(1, direction)
except TypeError:
raise TypeError("Invalid direction {0}".format(direction))
由于你真的只关心方向的标志,你可以使用它并消除任何错误检查。 0
的特殊情况将被视为1
,您可能希望为ValueError
筹集vector
。
如果你实际上不需要ax / ay / az或x / y / z,最好直接在axis
和axes
上执行操作,并让底层操作提升例外。这将使它能够进行鸭子打字。
修改:(更新axis
- > {{1}}了解问题中的新值)