Skip to content

Commit 6b5f1b4

Browse files
authored
bpo-37691: Let math.dist() accept sequences and iterables for coordinates (GH-14975)
1 parent 3221a63 commit 6b5f1b4

File tree

5 files changed

+47
-20
lines changed

5 files changed

+47
-20
lines changed

Doc/library/math.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,8 @@ Trigonometric functions
400400
.. function:: dist(p, q)
401401

402402
Return the Euclidean distance between two points *p* and *q*, each
403-
given as a tuple of coordinates. The two tuples must be the same size.
403+
given as a sequence (or iterable) of coordinates. The two points
404+
must have the same dimension.
404405

405406
Roughly equivalent to::
406407

Lib/test/test_math.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,10 @@ def testDist(self):
833833
sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q)))
834834
)
835835

836+
# Test non-tuple inputs
837+
self.assertEqual(dist([1.0, 2.0, 3.0], [4.0, 2.0, -1.0]), 5.0)
838+
self.assertEqual(dist(iter([1.0, 2.0, 3.0]), iter([4.0, 2.0, -1.0])), 5.0)
839+
836840
# Test allowable types (those with __float__)
837841
self.assertEqual(dist((14.0, 1.0), (2.0, -4.0)), 13.0)
838842
self.assertEqual(dist((14, 1), (2, -4)), 13)
@@ -873,8 +877,6 @@ class T(tuple):
873877
dist((1, 2, 3), (4, 5, 6), (7, 8, 9))
874878
with self.assertRaises(TypeError): # Scalars not allowed
875879
dist(1, 2)
876-
with self.assertRaises(TypeError): # Lists not allowed
877-
dist([1, 2, 3], [4, 5, 6])
878880
with self.assertRaises(TypeError): # Reject values without __float__
879881
dist((1.1, 'string', 2.2), (1, 2, 3))
880882
with self.assertRaises(ValueError): # Check dimension agree
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Let math.dist() accept coordinates as sequences (or iterables) rather than
2+
just tuples.

Modules/clinic/mathmodule.c.h

Lines changed: 3 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/mathmodule.c

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2427,31 +2427,49 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan)
24272427
/*[clinic input]
24282428
math.dist
24292429
2430-
p: object(subclass_of='&PyTuple_Type')
2431-
q: object(subclass_of='&PyTuple_Type')
2430+
p: object
2431+
q: object
24322432
/
24332433
24342434
Return the Euclidean distance between two points p and q.
24352435
2436-
The points should be specified as tuples of coordinates.
2437-
Both tuples must be the same size.
2436+
The points should be specified as sequences (or iterables) of
2437+
coordinates. Both inputs must have the same dimension.
24382438
24392439
Roughly equivalent to:
24402440
sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q)))
24412441
[clinic start generated code]*/
24422442

24432443
static PyObject *
24442444
math_dist_impl(PyObject *module, PyObject *p, PyObject *q)
2445-
/*[clinic end generated code: output=56bd9538d06bbcfe input=937122eaa5f19272]*/
2445+
/*[clinic end generated code: output=56bd9538d06bbcfe input=74e85e1b6092e68e]*/
24462446
{
24472447
PyObject *item;
24482448
double max = 0.0;
24492449
double x, px, qx, result;
24502450
Py_ssize_t i, m, n;
2451-
int found_nan = 0;
2451+
int found_nan = 0, p_allocated = 0, q_allocated = 0;
24522452
double diffs_on_stack[NUM_STACK_ELEMS];
24532453
double *diffs = diffs_on_stack;
24542454

2455+
if (!PyTuple_Check(p)) {
2456+
p = PySequence_Tuple(p);
2457+
if (p == NULL) {
2458+
return NULL;
2459+
}
2460+
p_allocated = 1;
2461+
}
2462+
if (!PyTuple_Check(q)) {
2463+
q = PySequence_Tuple(q);
2464+
if (q == NULL) {
2465+
if (p_allocated) {
2466+
Py_DECREF(p);
2467+
}
2468+
return NULL;
2469+
}
2470+
q_allocated = 1;
2471+
}
2472+
24552473
m = PyTuple_GET_SIZE(p);
24562474
n = PyTuple_GET_SIZE(q);
24572475
if (m != n) {
@@ -2482,12 +2500,24 @@ math_dist_impl(PyObject *module, PyObject *p, PyObject *q)
24822500
if (diffs != diffs_on_stack) {
24832501
PyObject_Free(diffs);
24842502
}
2503+
if (p_allocated) {
2504+
Py_DECREF(p);
2505+
}
2506+
if (q_allocated) {
2507+
Py_DECREF(q);
2508+
}
24852509
return PyFloat_FromDouble(result);
24862510

24872511
error_exit:
24882512
if (diffs != diffs_on_stack) {
24892513
PyObject_Free(diffs);
24902514
}
2515+
if (p_allocated) {
2516+
Py_DECREF(p);
2517+
}
2518+
if (q_allocated) {
2519+
Py_DECREF(q);
2520+
}
24912521
return NULL;
24922522
}
24932523

0 commit comments

Comments
 (0)