python:我如何创建一个二维向量对象,它可以初始化为x和y,或者角度?

我想能够初始化我的向量对象,无论是一个角度或x和y在python。我知道我可以用math.atan2(x, y)算出这个角,我也可以用这个角算出xy,但我不知道如何使这些输入可选。

我想打电话给他们中的任何一个:

1
Vector(x, y, speed)

或者:

1
Vector(angle, speed)

谢谢!


我认为最python化的方法是添加一个类方法:

1
2
3
4
5
6
7
8
class Vector:
    def __init__(x, y, speed):
        ...

    @classmethod
    def from_angle(cls, angle, speed):
        # figure out x and y from angle
        return cls(x, y, speed)

调用Vector(x, y, speed)Vector.from_angle(angle, speed)

,

各种变体如

1
2
def __init__(first, second, third=None)
   ...

1
2
def __init__(*args):
   ...

失去太多的清晰。使用您的代码的人(包括将来使用您的代码的人)将失去浏览方法签名和查看其选项的能力。


1
2
3
4
5
6
7
8
9
10
class Vector(object):
   """
    >>> Vector(angle, speed)  # initialize with angle and speed
    >>> Vector(x, y, speed)   # or initialize with x, y, and speed
   """

    def __init__(first, second, third=None):
        if third is None:
            angle, speed = first, second
        else:
            x, y, speed = first, second, third

如果使用两个参数调用,默认情况下third将是None。因此前两个参数将分配给anglespeed。否则,这些参数将被分配给xyspeed

(编辑:添加了一个doc字符串,因此Vector的调用签名是清晰的。)


作为一种替代方法,我将使用类方法来实现,因此构造函数只接受字段作为参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Vector(object):
    __slots__ = ['x', 'y']
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __repr__(self):
        return 'Vector({}, {})'.format(self.x, self.y)

    @classmethod
    def polarVector(cls, angle, mag):
        return cls(math.cos(angle) * mag, math.sin(angle) * mag)

    @classmethod
    def magVector(cls, x, y, mag):
        a = mag / math.sqrt(x**2 + y**2)
        return cls(x * a, y * a)

可选参数的问题

可选参数的主要问题是代码的清晰性。

1
2
3
4
5
6
7
a = Vector(1, 2)             # Is 1"angle" or"x"?
a = Vector(3, 4, 10)         # Huh?

# These functions do different things,
# so it makes sense that they have different names.
a = Vector.polarVector(1, 2)
a = Vector.magVector(3, 4, 10)


unutbu和Pavel Anossov的回答都很好。

我个人更喜欢将坐标作为元组传递(因为它们毕竟是一个向量,并且属于一起)。因此,你总是会有两个论点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#! /usr/bin/python3.2

import math

class Vector:
    def __init__ (self, direction, speed):
        self.speed = speed
        try: self.angle = math.atan2 (direction [0], direction [1] )
        except: self.angle = direction

v1 = Vector (math.pi / 4, 100)
print (v1.angle)

v2 = Vector ( (1, 1), 100)
print (v2.angle)