使用 Python 元组作为向量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2576296/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using Python tuples as vectors
提问by Etaoin
I need to represent immutable vectors in Python ("vectors" as in linear algebra, not as in programming). The tuple seems like an obvious choice.
我需要在 Python 中表示不可变向量(线性代数中的“向量”,而不是编程中的“向量”)。元组似乎是一个显而易见的选择。
The trouble is when I need to implement things like addition and scalar multiplication. If a
and b
are vectors, and c
is a number, the best I can think of is this:
问题是当我需要实现加法和标量乘法之类的东西时。如果a
和b
是向量,并且c
是一个数字,我能想到的最好的就是这个:
tuple(map(lambda x,y: x + y, a, b)) # add vectors 'a' and 'b'
tuple(map(lambda x: x * c, a)) # multiply vector 'a' by scalar 'c'
which seems inelegant; there should be a clearer, simpler way to get this done -- not to mention avoiding the call to tuple
, since map
returns a list.
这看起来不优雅;应该有一种更清晰、更简单的方法来完成这项工作——更不用说避免调用tuple
,因为map
返回一个列表。
Is there a better option?
有更好的选择吗?
回答by Alex Martelli
Immutable types are pretty rare in Python and third-party extensions thereof; the OP rightly claims "there are enough uses for linear algebra that it doesn't seem likely I have to roll my own" -- but all the existing types I know that do linear algebra are mutable! So, as the OP is adamant on immutability, there isnothing for it but the roll-your-own route.
不可变类型在 Python 及其第三方扩展中非常罕见;OP 正确地声称“线性代数有足够的用途,我似乎不必自己动手”——但我知道的所有现有的线性代数类型都是可变的!因此,随着OP是不变性坚信,有是什么好说的了,但卷制自己的路线。
Not that there's all that much rolling involved, e.g. if you specifically need 2-d vectors:
并不是说涉及那么多滚动,例如,如果您特别需要二维向量:
import math
class ImmutableVector(object):
__slots__ = ('_d',)
def __init__(self, x, y):
object.__setattr__(self, _d, (x, y))
def __setattr__(self, n, v):
raise ValueError("Can't alter instance of %s" % type(self))
@property
def x(self):
return self._d[0]
@property
def y(self):
return self._d[1]
def __eq__(self, other):
return self._d == other._d
def __ne__(self, other):
return self._d != other._d
def __hash__(self):
return hash(self._d)
def __add__(self, other):
return type(self)(self.x+other.x, self.y+other.y)
def __mul__(self, scalar):
return type(self)(self.x*scalar, self.y*scalar)
def __repr__(self):
return '%s(%s, %s)' % (type(self).__name__, self.x, self.y)
def __abs__(self):
return math.hypot(self.x, self.y)
I "threw in for free" a few extras such as .x
and .y
R/O properties, nice string representation, usability in sets or as keys in dicts (why else would one want immutability?-), low memory footprint, abs(v)
to give v
's vector-length -- I'm sure you can think of other "wouldn't-it-be-cool-if" methods and operators, depending on your application field, and they'll be just as easy. If you need other dimensionalities it won't be much harder, though a tad less readable since the .x
, .y
notation doesn't apply any more;-) (but I'd use genexps, not map
).
我“免费提供”了一些额外的东西,例如.x
和.y
R/O 属性、漂亮的字符串表示、集合中的可用性或作为 dicts 中的键(为什么还想要不变性?-)、低内存占用,abs(v)
以提供v
的向量-length -- 我相信您可以想到其他“wouldn't-it-be-cool-if”方法和运算符,具体取决于您的应用领域,它们将同样简单。如果您需要其他维度,它不会更难,尽管由于.x
,.y
符号不再适用,因此可读性稍差;- map
) (但我会使用 genexps,而不是)。
回答by Ignacio Vazquez-Abrams
回答by Ignacio Vazquez-Abrams
By inheriting from tuple, you can make a nice Vector class pretty easily. Here's enough code to provide addition of vectors, and multiplication of a vector by a scalar. It gives you arbitrary length vectors, and can work with complex numbers, ints, or floats.
通过从 tuple 继承,你可以很容易地创建一个漂亮的 Vector 类。这里有足够的代码来提供向量的加法,以及向量与标量的乘法。它为您提供任意长度的向量,并且可以处理复数、整数或浮点数。
class Vector(tuple):
def __add__(self, a):
# TODO: check lengths are compatable.
return Vector(x + y for x, y in zip(self, a))
def __mul__(self, c):
return Vector(x * c for x in self)
def __rmul__(self, c):
return Vector(c * x for x in self)
a = Vector((1, 2, 3))
b = Vector((2, 3, 4))
print a + b
print 3 * a
print a * 3
回答by OnurC
Although using a library like NumPy seems to be the resolution for the OP, I think there is still some value in a simple solution which does not require additional libraries and which you can stay immutable, with iterables.
虽然使用像 NumPy 这样的库似乎是 OP 的解决方案,但我认为一个简单的解决方案仍然有一些价值,它不需要额外的库,并且可以通过迭代保持不变。
Using the itertools
and operators
modules:
使用itertools
和operators
模块:
imap(add, a, b) # returns iterable to sum of a and b vectors
This implementation is simple. It does not use lambda neither any list-tuple conversion as it is iterator based.
这个实现很简单。它不使用 lambda,也不使用任何列表元组转换,因为它是基于迭代器的。
from itertools import imap
from operator import add
vec1 = (1, 2, 3)
vec2 = (10, 20, 30)
result = imap(add, vec1, vec2)
print(tuple(result))
Yields:
产量:
(11, 22, 33)
回答by Gordon Gustafson
Why not create your own class, making use of 2 Cartesian point member variables? (sorry if the syntax is a little off, my python is rusty)
为什么不创建自己的类,使用 2 个笛卡尔点成员变量?(对不起,如果语法有点不对,我的python 生锈了)
class point:
def __init__(self,x,y):
self.x=x
self.y=y
#etc
def add(self,p):
return point(self.x + p.x, self.y + p.y)
class vector:
def __init__(self,a,b):
self.pointA=a
self.pointB=b
#etc
def add(self,v):
return vector(self.pointA + v.pointA, self.pointB + v.pointB)
回答by maxschlepzig
For occasional use, a Python 3 solution without repeating lambdas is possible via using the standard operator package:
对于偶尔使用,通过使用标准运算符包可以实现不重复 lambda 的 Python 3 解决方案:
from operator import add, mul
a = (1, 2, 3)
b = (4, 5, 6)
print(tuple(map(add, a , b)))
print(tuple(map(mul, a , b)))
which prints:
打印:
(5, 7, 9)
(4, 10, 18)
For serious linear algebra computations using numpy vectors is the canonical solution:
对于使用 numpy 向量的严肃线性代数计算是规范的解决方案:
import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(a+b)
print(a*b)
which prints:
打印:
[5 7 9]
[ 4 10 18]
回答by sblom
Since pretty much all of the sequence manipulation functions return lists, that's pretty much what you're going to have to do.
由于几乎所有的序列操作函数都返回列表,这就是您必须要做的。