Skip to content

Commit 4668b00

Browse files
committed
Implement PEP 238 in its (almost) full glory.
This introduces: - A new operator // that means floor division (the kind of division where 1/2 is 0). - The "future division" statement ("from __future__ import division) which changes the meaning of the / operator to implement "true division" (where 1/2 is 0.5). - New overloadable operators __truediv__ and __floordiv__. - New slots in the PyNumberMethods struct for true and floor division, new abstract APIs for them, new opcodes, and so on. I emphasize that without the future division statement, the semantics of / will remain unchanged until Python 3.0. Not yet implemented are warnings (default off) when / is used with int or long arguments. This has been on display since 7/31 as SF patch #443474. Flames to /dev/null.
1 parent 074c9d2 commit 4668b00

19 files changed

Lines changed: 476 additions & 226 deletions

Grammar/Grammar

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ stmt: simple_stmt | compound_stmt
3838
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
3939
small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt
4040
expr_stmt: testlist (augassign testlist | ('=' testlist)*)
41-
augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**='
41+
augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//='
4242
# For normal assignments, additional restrictions enforced by the interpreter
4343
print_stmt: 'print' ( [ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ] )
4444
del_stmt: 'del' exprlist
@@ -77,7 +77,7 @@ xor_expr: and_expr ('^' and_expr)*
7777
and_expr: shift_expr ('&' shift_expr)*
7878
shift_expr: arith_expr (('<<'|'>>') arith_expr)*
7979
arith_expr: term (('+'|'-') term)*
80-
term: factor (('*'|'/'|'%') factor)*
80+
term: factor (('*'|'/'|'%'|'//') factor)*
8181
factor: ('+'|'-'|'~') factor | power
8282
power: atom trailer* ('**' factor)*
8383
atom: '(' [testlist] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+

Include/abstract.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,26 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
547547
548548
*/
549549

550+
DL_IMPORT(PyObject *) PyNumber_FloorDivide(PyObject *o1, PyObject *o2);
551+
552+
/*
553+
Returns the result of dividing o1 by o2 giving an integral result,
554+
or null on failure.
555+
This is the equivalent of the Python expression: o1//o2.
556+
557+
558+
*/
559+
560+
DL_IMPORT(PyObject *) PyNumber_TrueDivide(PyObject *o1, PyObject *o2);
561+
562+
/*
563+
Returns the result of dividing o1 by o2 giving a float result,
564+
or null on failure.
565+
This is the equivalent of the Python expression: o1/o2.
566+
567+
568+
*/
569+
550570
DL_IMPORT(PyObject *) PyNumber_Remainder(PyObject *o1, PyObject *o2);
551571

552572
/*
@@ -742,6 +762,28 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
742762
743763
*/
744764

765+
DL_IMPORT(PyObject *) PyNumber_InPlaceFloorDivide(PyObject *o1,
766+
PyObject *o2);
767+
768+
/*
769+
Returns the result of dividing o1 by o2 giving an integral result,
770+
possibly in-place, or null on failure.
771+
This is the equivalent of the Python expression:
772+
o1 /= o2.
773+
774+
*/
775+
776+
DL_IMPORT(PyObject *) PyNumber_InPlaceTrueDivide(PyObject *o1,
777+
PyObject *o2);
778+
779+
/*
780+
Returns the result of dividing o1 by o2 giving a float result,
781+
possibly in-place, or null on failure.
782+
This is the equivalent of the Python expression:
783+
o1 /= o2.
784+
785+
*/
786+
745787
DL_IMPORT(PyObject *) PyNumber_InPlaceRemainder(PyObject *o1, PyObject *o2);
746788

747789
/*

Include/compile.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ typedef struct {
4141
effect, this passes on the "from __future__ import generators" state
4242
in effect when the code block was compiled. */
4343
#define CO_GENERATOR_ALLOWED 0x1000
44+
/* XXX Ditto for future division */
45+
#define CO_FUTURE_DIVISION 0x2000
4446

4547
extern DL_IMPORT(PyTypeObject) PyCode_Type;
4648

@@ -64,6 +66,7 @@ typedef struct {
6466
int ff_last_lineno;
6567
int ff_nested_scopes;
6668
int ff_generators;
69+
int ff_division;
6770
} PyFutureFeatures;
6871

6972
DL_IMPORT(PyFutureFeatures *) PyNode_Future(struct _node *, char *);
@@ -76,6 +79,9 @@ DL_IMPORT(PyCodeObject *) PyNode_CompileFlags(struct _node *, char *,
7679
#define GENERATORS_DEFAULT 0
7780
#define FUTURE_GENERATORS "generators"
7881

82+
#define DIVISION_DEFAULT 0
83+
#define FUTURE_DIVISION "division"
84+
7985
/* for internal use only */
8086
#define _PyCode_GETCODEPTR(co, pp) \
8187
((*(co)->co_code->ob_type->tp_as_buffer->bf_getreadbuffer) \

Include/object.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ typedef struct {
161161
binaryfunc nb_inplace_and;
162162
binaryfunc nb_inplace_xor;
163163
binaryfunc nb_inplace_or;
164+
165+
/* The following require the Py_TPFLAGS_HAVE_CLASS flag */
166+
binaryfunc nb_floor_divide;
167+
binaryfunc nb_true_divide;
168+
binaryfunc nb_inplace_floor_divide;
169+
binaryfunc nb_inplace_true_divide;
164170
} PyNumberMethods;
165171

166172
typedef struct {
@@ -396,7 +402,7 @@ given type object has a specified feature.
396402
/* tp_iter is defined */
397403
#define Py_TPFLAGS_HAVE_ITER (1L<<7)
398404

399-
/* Experimental stuff for healing the type/class split */
405+
/* New members introduced by Python 2.2 exist */
400406
#define Py_TPFLAGS_HAVE_CLASS (1L<<8)
401407

402408
/* Set if the type object is dynamically allocated */

Include/opcode.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ extern "C" {
2929
#define BINARY_ADD 23
3030
#define BINARY_SUBTRACT 24
3131
#define BINARY_SUBSCR 25
32+
#define BINARY_FLOOR_DIVIDE 26
33+
#define BINARY_TRUE_DIVIDE 27
34+
#define INPLACE_FLOOR_DIVIDE 28
35+
#define INPLACE_TRUE_DIVIDE 29
3236

3337
#define SLICE 30
3438
/* Also uses 31-33 */

Include/pythonrun.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ extern "C" {
1212
accordingly then. */
1313
#define PyCF_NESTED_SCOPES (0x00000001UL)
1414
#define PyCF_GENERATORS (0x00000002UL)
15+
#define PyCF_DIVISION (0x00000004UL)
1516
typedef struct {
1617
unsigned long cf_flags; /* bitmask of PyCF_xxx flags */
1718
} PyCompilerFlags;

Include/token.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,12 @@ extern "C" {
5555
#define LEFTSHIFTEQUAL 45
5656
#define RIGHTSHIFTEQUAL 46
5757
#define DOUBLESTAREQUAL 47
58+
#define DOUBLESLASH 48
59+
#define DOUBLESLASHEQUAL 49
5860
/* Don't forget to update the table _PyParser_TokenNames in tokenizer.c! */
59-
#define OP 48
60-
#define ERRORTOKEN 49
61-
#define N_TOKENS 50
61+
#define OP 50
62+
#define ERRORTOKEN 51
63+
#define N_TOKENS 52
6264

6365
/* Special definitions for cooperation with parser */
6466

Lib/__future__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,4 @@ def __repr__(self):
6868

6969
nested_scopes = _Feature((2, 1, 0, "beta", 1), (2, 2, 0, "alpha", 0))
7070
generators = _Feature((2, 2, 0, "alpha", 1), (2, 3, 0, "final", 0))
71+
division = _Feature((2, 2, 0, "alpha", 2), (3, 0, 0, "alpha", 0))

Objects/abstract.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,20 @@ PyNumber_Add(PyObject *v, PyObject *w)
564564
return result;
565565
}
566566

567+
PyObject *
568+
PyNumber_FloorDivide(PyObject *v, PyObject *w)
569+
{
570+
/* XXX tp_flags test */
571+
return binary_op(v, w, NB_SLOT(nb_floor_divide), "//");
572+
}
573+
574+
PyObject *
575+
PyNumber_TrueDivide(PyObject *v, PyObject *w)
576+
{
577+
/* XXX tp_flags test */
578+
return binary_op(v, w, NB_SLOT(nb_true_divide), "/");
579+
}
580+
567581
PyObject *
568582
PyNumber_Remainder(PyObject *v, PyObject *w)
569583
{
@@ -630,6 +644,22 @@ INPLACE_BINOP(PyNumber_InPlaceRshift, nb_inplace_rshift, nb_rshift, ">>=")
630644
INPLACE_BINOP(PyNumber_InPlaceSubtract, nb_inplace_subtract, nb_subtract, "-=")
631645
INPLACE_BINOP(PyNumber_InPlaceDivide, nb_inplace_divide, nb_divide, "/=")
632646

647+
PyObject *
648+
PyNumber_InPlaceFloorDivide(PyObject *v, PyObject *w)
649+
{
650+
/* XXX tp_flags test */
651+
return binary_iop(v, w, NB_SLOT(nb_inplace_floor_divide),
652+
NB_SLOT(nb_floor_divide), "//=");
653+
}
654+
655+
PyObject *
656+
PyNumber_InPlaceTrueDivide(PyObject *v, PyObject *w)
657+
{
658+
/* XXX tp_flags test */
659+
return binary_iop(v, w, NB_SLOT(nb_inplace_true_divide),
660+
NB_SLOT(nb_true_divide), "/=");
661+
}
662+
633663
PyObject *
634664
PyNumber_InPlaceAdd(PyObject *v, PyObject *w)
635665
{

Objects/classobject.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,6 +1435,8 @@ BINARY(instance_mul, "mul", PyNumber_Multiply)
14351435
BINARY(instance_div, "div", PyNumber_Divide)
14361436
BINARY(instance_mod, "mod", PyNumber_Remainder)
14371437
BINARY(instance_divmod, "divmod", PyNumber_Divmod)
1438+
BINARY(instance_floordiv, "floordiv", PyNumber_FloorDivide)
1439+
BINARY(instance_truediv, "truediv", PyNumber_TrueDivide)
14381440

14391441
BINARY_INPLACE(instance_ior, "or", PyNumber_InPlaceOr)
14401442
BINARY_INPLACE(instance_ixor, "xor", PyNumber_InPlaceXor)
@@ -1446,6 +1448,8 @@ BINARY_INPLACE(instance_isub, "sub", PyNumber_InPlaceSubtract)
14461448
BINARY_INPLACE(instance_imul, "mul", PyNumber_InPlaceMultiply)
14471449
BINARY_INPLACE(instance_idiv, "div", PyNumber_InPlaceDivide)
14481450
BINARY_INPLACE(instance_imod, "mod", PyNumber_InPlaceRemainder)
1451+
BINARY_INPLACE(instance_ifloordiv, "floordiv", PyNumber_InPlaceFloorDivide)
1452+
BINARY_INPLACE(instance_itruediv, "truediv", PyNumber_InPlaceTrueDivide)
14491453

14501454
/* Try a 3-way comparison, returning an int; v is an instance. Return:
14511455
-2 for an exception;
@@ -1900,6 +1904,10 @@ static PyNumberMethods instance_as_number = {
19001904
(binaryfunc)instance_iand, /* nb_inplace_and */
19011905
(binaryfunc)instance_ixor, /* nb_inplace_xor */
19021906
(binaryfunc)instance_ior, /* nb_inplace_or */
1907+
(binaryfunc)instance_floordiv, /* nb_floor_divide */
1908+
(binaryfunc)instance_truediv, /* nb_true_divide */
1909+
(binaryfunc)instance_ifloordiv, /* nb_inplace_floor_divide */
1910+
(binaryfunc)instance_itruediv, /* nb_inplace_true_divide */
19031911
};
19041912

19051913
PyTypeObject PyInstance_Type = {

0 commit comments

Comments
 (0)