8000 bpo-37691: Let math.dist() accept sequences and iterables for coordin… · python/cpython@76821ba · GitHub
[go: up one dir, main page]

Skip to content
< 8000 /react-partial>

Commit 76821ba

Browse files
bpo-37691: Let math.dist() accept sequences and iterables for coordinates (GH-14975) (GH-14984)
(cherry picked from commit 6b5f1b4) Co-authored-by: Raymond Hettinger <rhettinger@users.noreply.github.com>
1 parent 1710193 commit 76821ba

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
@@ -394,7 +394,8 @@ Trigonometric functions
394394
.. function:: dist(p, q)
395395

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

399400
Roughly equivalent to::
400401

Lib/test/test_math.py

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

829+
# Test non-tuple inputs
830+
self.assertEqual(dist([1.0, 2.0, 3.0], [4.0, 2.0, -1.0]), 5.0)
831+
self.assertEqual(dist(iter([1.0, 2.0, 3.0]), iter([4.0, 2.0, -1.0])), 5.0)
832+
829833
# Test allowable types (those with __float__)
830834
self.assertEqual(dist((14.0, 1.0), (2.0, -4.0)), 13.0)
831835
self.assertEqual(dist((14, 1), (2, -4)), 13)
@@ -866,8 +870,6 @@ class T(tuple):
866870
dist((1, 2, 3), (4, 5, 6), (7, 8, 9))
867871
with self.assertRaises(TypeError): # Scalars not allowed
868872
dist(1, 2)
869-
with self.assertRaises(TypeError): # Lists not allowed
870-
dist([1, 2, 3], [4, 5, 6])
871873
with self.assertRaises(TypeError): # Reject values without __float__
872874
dist((1.1, 'string', 2.2), (1, 2, 3))
873875
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
@@ -2418,31 +2418,49 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan)
24182418
/*[clinic input]
24192419
math.dist
24202420
2421-
p: object(subclass_of='&PyTuple_Type')
2422-
q: object(subclass_of='&PyTuple_Type')
2421+
p: object
2422+
q: object
24232423
/
24242424
24252425
Return the Euclidean distance between two points p and q.
24262426
2427-
The points should be specified as tuples of coordinates.
2428-
Both tuples must be the same size.
2427+
The points should be specified as sequences (or iterables) of
2428+
coordinates. Both inputs must have the same dimension.
24292429
24302430
Roughly equivalent to:
24312431
sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q)))
24322432
[clinic start generated code]*/
24332433

24342434
static PyObject *
24352435
math_dist_impl(PyObject *module, PyObject *p, PyObject *q)
2436-
/*[clinic end generated code: output=56bd9538d06bbcfe input=937122eaa5f19272]*/
2436+
/*[clinic end generated code: output=56bd9538d06bbcfe input=74e85e1b6092e68e]*/
24372437
{
24382438
PyObject *item;
24392439
double max = 0.0;
24402440
double x, px, qx, result;
24412441
Py_ssize_t i, m, n;
2442-
int found_nan = 0;
2442+
int found_nan = 0, p_allocated = 0, q_allocated = 0;
24432443
double diffs_on_stack[NUM_STACK_ELEMS];
24442444
double *diffs = diffs_on_stack;
24452445

2446+
if (!PyTuple_Check(p)) {
2447+
p = PySequence_Tuple(p);
2448+
if (p == NULL) {
2449+
return NULL;
2450+
}
2451+
p_allocated = 1;
2452+
}
2453+
if (!PyTuple_Check(q)) {
2454+
q = PySequence_Tuple(q);
2455+
if (q == NULL) {
2456+
if (p_allocated) {
2457+
Py_DECREF(p);
2458+
}
2459+
return NULL;
2460+
}
2461+
q_allocated = 1;
2462+
}
2463+
24462464
m = PyTuple_GET_SIZE(p);
24472465
n = PyTuple_GET_SIZE(q);
24482466
if (m != n) {
@@ -2473,12 +2491,24 @@ math_dist_impl(PyObject *module, PyObject *p, PyObject *q)
24732491
if (diffs != diffs_on_stack) {
24742492
PyObject_Free(diffs);
24752493
}
2494+
if (p_allocated) {
2495+
Py_DECREF(p);
2496+
}
2497+
if (q_allocated) {
2498+
Py_DECREF(q);
2499+
}
24762500
return PyFloat_FromDouble(result);
24772501

24782502
error_exit:
24792503
if (diffs != diffs_on_stack) {
24802504
PyObject_Free(diffs);
24812505
}
2506+
if (p_allocated) {
2507+
Py_DECREF(p);
2508+
}
2509+
if (q_allocated) {
2510+
Py_DECREF(q);
2511+
}
24822512
return NULL;
24832513
}
24842514

0 commit comments

Comments
 (0)
0