Guido van Rossum schrieb:
On 6/10/07, Nick Coghlan <[EMAIL PROTECTED]> wrote:
Guido van Rossum wrote:
> On 6/10/07, Georg Brandl <[EMAIL PROTECTED]> wrote:
>> Guido van Rossum schrieb:
>>> Very cool; thanks!!! No problems so far.
>>>
>>> I wonder if we need a bin() built-in that is to 0b like oct() is to 0o
>>> and hex() to 0x?
>> Would that also require a __bin__() special method?
>
> If the other two use it, we might as well model it that way.
I must admit I've never understood why hex() and oct() don't just go
through __int__() (Note that the integer formats are all defined as
going through int() in PEP 3101).
If we only want them to work for true integers, then we have __index__()
available now.
Well, maybe it's time to kill __oct__ and __hex__ then.
Okay, attached is a patch to do that.
It adds a new abstract function, PyNumber_ToBase, that converts an __index__able
integer to an arbitrary base. bin(), oct() and hex() just uses it.
(I've left the slots in the PyNumberMethods struct for now.)
There was not much library code to change: only tests used the special methods.
Though /me wonders if we shouldn't just expose PyNumber_ToBase as a single
function that mirrors int(str, base).
Georg
--
Thus spake the Lord: Thou shalt indent with four spaces. No more, no less.
Four shall be the number of spaces thou shalt indent, and the number of thy
indenting shall be four. Eight shalt thou not indent, nor either indent thou
two, excepting that thou then proceed to four. Tabs are right out.
Index: Python/bltinmodule.c
===================================================================
--- Python/bltinmodule.c (Revision 55885)
+++ Python/bltinmodule.c (Arbeitskopie)
@@ -247,6 +247,18 @@
static PyObject *
+builtin_bin(PyObject *self, PyObject *v)
+{
+ return PyNumber_ToBase(v, 2);
+}
+
+PyDoc_STRVAR(bin_doc,
+"bin(number) -> string\n\
+\n\
+Return the binary representation of an integer or long integer.");
+
+
+static PyObject *
builtin_filter(PyObject *self, PyObject *args)
{
PyObject *func, *seq, *result, *it, *arg;
@@ -1230,24 +1242,7 @@
static PyObject *
builtin_hex(PyObject *self, PyObject *v)
{
- PyNumberMethods *nb;
- PyObject *res;
-
- if ((nb = v->ob_type->tp_as_number) == NULL ||
- nb->nb_hex == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "hex() argument can't be converted to hex");
- return NULL;
- }
- res = (*nb->nb_hex)(v);
- if (res && !PyString_Check(res)) {
- PyErr_Format(PyExc_TypeError,
- "__hex__ returned non-string (type %.200s)",
- res->ob_type->tp_name);
- Py_DECREF(res);
- return NULL;
- }
- return res;
+ return PyNumber_ToBase(v, 16);
}
PyDoc_STRVAR(hex_doc,
@@ -1430,24 +1425,7 @@
static PyObject *
builtin_oct(PyObject *self, PyObject *v)
{
- PyNumberMethods *nb;
- PyObject *res;
-
- if (v == NULL || (nb = v->ob_type->tp_as_number) == NULL ||
- nb->nb_oct == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "oct() argument can't be converted to oct");
- return NULL;
- }
- res = (*nb->nb_oct)(v);
- if (res && !PyString_Check(res)) {
- PyErr_Format(PyExc_TypeError,
- "__oct__ returned non-string (type %.200s)",
- res->ob_type->tp_name);
- Py_DECREF(res);
- return NULL;
- }
- return res;
+ return PyNumber_ToBase(v, 8);
}
PyDoc_STRVAR(oct_doc,
@@ -1949,6 +1927,7 @@
{"abs", builtin_abs, METH_O, abs_doc},
{"all", builtin_all, METH_O, all_doc},
{"any", builtin_any, METH_O, any_doc},
+ {"bin", builtin_bin, METH_O, bin_doc},
{"chr", builtin_chr, METH_VARARGS, chr_doc},
{"cmp", builtin_cmp, METH_VARARGS, cmp_doc},
{"compile", (PyCFunction)builtin_compile, METH_VARARGS | METH_KEYWORDS, compile_doc},
Index: Include/abstract.h
===================================================================
--- Include/abstract.h (Revision 55885)
+++ Include/abstract.h (Arbeitskopie)
@@ -851,7 +851,15 @@
expression: o1 |= o2.
*/
+ PyAPI_FUNC(PyObject *) PyNumber_ToBase(PyObject *n, int base);
+ /*
+ Returns the integer n converted to a string with a base, with a base
+ marker of 0b, 0o or 0x prefixed if applicable.
+ If n is not an int object, it is converted with PyNumber_Index first.
+ */
+
+
/* Sequence protocol:*/
PyAPI_FUNC(int) PySequence_Check(PyObject *o);
Index: Include/longobject.h
===================================================================
--- Include/longobject.h (Revision 55885)
+++ Include/longobject.h (Arbeitskopie)
@@ -111,6 +111,11 @@
unsigned char* bytes, size_t n,
int little_endian, int is_signed);
+
+/* _PyLong_Format: Convert the long to a string object with given base,
+ appending a base prefix of 0[box] if base is 2, 8 or 16. */
+PyAPI_FUNC(PyObject *) _PyLong_Format(PyObject *aa, int base);
+
#ifdef __cplusplus
}
#endif
Index: Objects/abstract.c
===================================================================
--- Objects/abstract.c (Revision 55885)
+++ Objects/abstract.c (Arbeitskopie)
@@ -971,6 +971,22 @@
return PyFloat_FromString(o);
}
+
+PyObject *
+PyNumber_ToBase(PyObject *n, int base)
+{
+ PyObject *res;
+ PyObject *index = PyNumber_Index(n);
+
+ if (!index)
+ return NULL;
+ assert(PyLong_Check(index));
+ res = _PyLong_Format(index, base);
+ Py_DECREF(index);
+ return res;
+}
+
+
/* Operations on sequences */
int
Index: Objects/typeobject.c
===================================================================
--- Objects/typeobject.c (Revision 55885)
+++ Objects/typeobject.c (Arbeitskopie)
@@ -3236,8 +3236,6 @@
COPYNUM(nb_int);
COPYNUM(nb_long);
COPYNUM(nb_float);
- COPYNUM(nb_oct);
- COPYNUM(nb_hex);
COPYNUM(nb_inplace_add);
COPYNUM(nb_inplace_subtract);
COPYNUM(nb_inplace_multiply);
@@ -4556,8 +4554,6 @@
SLOT0(slot_nb_int, "__int__")
SLOT0(slot_nb_long, "__long__")
SLOT0(slot_nb_float, "__float__")
-SLOT0(slot_nb_oct, "__oct__")
-SLOT0(slot_nb_hex, "__hex__")
SLOT1(slot_nb_inplace_add, "__iadd__", PyObject *, "O")
SLOT1(slot_nb_inplace_subtract, "__isub__", PyObject *, "O")
SLOT1(slot_nb_inplace_multiply, "__imul__", PyObject *, "O")
@@ -5208,10 +5204,6 @@
"long(x)"),
UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc,
"float(x)"),
- UNSLOT("__oct__", nb_oct, slot_nb_oct, wrap_unaryfunc,
- "oct(x)"),
- UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc,
- "hex(x)"),
NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc,
"x[y:z] <==> x[y.__index__():z.__index__()]"),
IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add,
Index: Objects/intobject.c
===================================================================
--- Objects/intobject.c (Revision 55885)
+++ Objects/intobject.c (Arbeitskopie)
@@ -922,30 +922,6 @@
}
static PyObject *
-int_oct(PyIntObject *v)
-{
- char buf[100];
- long x = v -> ob_ival;
- if (x < 0)
- PyOS_snprintf(buf, sizeof(buf), "-0o%lo", -x);
- else
- PyOS_snprintf(buf, sizeof(buf), "0o%lo", x);
- return PyString_FromString(buf);
-}
-
-static PyObject *
-int_hex(PyIntObject *v)
-{
- char buf[100];
- long x = v -> ob_ival;
- if (x < 0)
- PyOS_snprintf(buf, sizeof(buf), "-0x%lx", -x);
- else
- PyOS_snprintf(buf, sizeof(buf), "0x%lx", x);
- return PyString_FromString(buf);
-}
-
-static PyObject *
int_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
static PyObject *
@@ -1072,8 +1048,8 @@
(unaryfunc)int_int, /*nb_int*/
(unaryfunc)int_long, /*nb_long*/
(unaryfunc)int_float, /*nb_float*/
- (unaryfunc)int_oct, /*nb_oct*/
- (unaryfunc)int_hex, /*nb_hex*/
+ 0, /*nb_oct*/ /* not in use */
+ 0, /*nb_hex*/ /* not in use */
0, /*nb_inplace_add*/
0, /*nb_inplace_subtract*/
0, /*nb_inplace_multiply*/
Index: Objects/longobject.c
===================================================================
--- Objects/longobject.c (Revision 55885)
+++ Objects/longobject.c (Arbeitskopie)
@@ -80,7 +80,6 @@
static PyLongObject *mul1(PyLongObject *, wdigit);
static PyLongObject *muladd1(PyLongObject *, wdigit, wdigit);
static PyLongObject *divrem1(PyLongObject *, digit, digit *);
-static PyObject *long_format(PyObject *aa, int base);
#define SIGCHECK(PyTryBlock) \
if (--_Py_Ticker < 0) { \
@@ -1384,7 +1383,7 @@
/* Divide long pin, w/ size digits, by non-zero digit n, storing quotient
in pout, and returning the remainder. pin and pout point at the LSD.
It's OK for pin == pout on entry, which saves oodles of mallocs/frees in
- long_format, but that should be done with great care since longs are
+ _PyLong_Format, but that should be done with great care since longs are
immutable. */
static digit
@@ -1426,8 +1425,8 @@
Return a string object.
If base is 2, 8 or 16, add the proper prefix '0b', '0o' or '0x'. */
-static PyObject *
-long_format(PyObject *aa, int base)
+PyObject *
+_PyLong_Format(PyObject *aa, int base)
{
register PyLongObject *a = (PyLongObject *)aa;
PyStringObject *str;
@@ -2154,7 +2153,7 @@
static PyObject *
long_repr(PyObject *v)
{
- return long_format(v, 10);
+ return _PyLong_Format(v, 10);
}
static int
@@ -3513,18 +3512,6 @@
}
static PyObject *
-long_oct(PyObject *v)
-{
- return long_format(v, 8);
-}
-
-static PyObject *
-long_hex(PyObject *v)
-{
- return long_format(v, 16);
-}
-
-static PyObject *
long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
static PyObject *
@@ -3648,8 +3635,8 @@
long_int, /*nb_int*/
long_long, /*nb_long*/
long_float, /*nb_float*/
- long_oct, /*nb_oct*/
- long_hex, /*nb_hex*/
+ 0, /*nb_oct*/ /* not used */
+ 0, /*nb_hex*/ /* not used */
0, /* nb_inplace_add */
0, /* nb_inplace_subtract */
0, /* nb_inplace_multiply */
Index: Objects/stringobject.c
===================================================================
--- Objects/stringobject.c (Revision 55885)
+++ Objects/stringobject.c (Arbeitskopie)
@@ -4255,12 +4255,12 @@
break;
case 'o':
numnondigits = 2;
- result = val->ob_type->tp_as_number->nb_oct(val);
+ result = PyNumber_ToBase(val, 8);
break;
case 'x':
case 'X':
numnondigits = 2;
- result = val->ob_type->tp_as_number->nb_hex(val);
+ result = PyNumber_ToBase(val, 16);
break;
default:
assert(!"'type' not in [duoxX]");
Index: Lib/test/output/test_class
===================================================================
--- Lib/test/output/test_class (Revision 55885)
+++ Lib/test/output/test_class (Arbeitskopie)
@@ -46,8 +46,7 @@
__int__: ()
__int__: ()
__float__: ()
-__oct__: ()
-__hex__: ()
+__index__: ()
__hash__: ()
__repr__: ()
__str__: ()
Index: Lib/test/test_class.py
===================================================================
--- Lib/test/test_class.py (Revision 55885)
+++ Lib/test/test_class.py (Arbeitskopie)
@@ -80,18 +80,14 @@
print("__int__:", args)
return 1
+ def __index__(self, *args):
+ print("__index__:", args)
+ return 1
+
def __float__(self, *args):
print("__float__:", args)
return 1.0
- def __oct__(self, *args):
- print("__oct__:", args)
- return '01'
-
- def __hex__(self, *args):
- print("__hex__:", args)
- return '0x1'
-
def __cmp__(self, *args):
print("__cmp__:", args)
return 0
@@ -237,7 +233,6 @@
int(testme)
float(testme)
oct(testme)
-hex(testme)
# And the rest...
@@ -287,8 +282,6 @@
__float__ = __int__
__str__ = __int__
__repr__ = __int__
- __oct__ = __int__
- __hex__ = __int__
def check_exc(stmt, exception):
"""Raise TestFailed if executing 'stmt' does not raise 'exception'
Index: Lib/test/test_format.py
===================================================================
--- Lib/test/test_format.py (Revision 55885)
+++ Lib/test/test_format.py (Arbeitskopie)
@@ -233,14 +233,6 @@
test_exc(u'no format', u'1', TypeError,
"not all arguments converted during string formatting")
-class Foobar(int):
- def __oct__(self):
- # Returning a non-string should not blow up.
- return self + 1
-
-test_exc('%o', Foobar(), TypeError,
- "expected string or Unicode object, int found")
-
if maxsize == 2**31-1:
# crashes 2.2.1 and earlier:
try:
_______________________________________________
Python-3000 mailing list
Python-3000@python.org
http://mail.python.org/mailman/listinfo/python-3000
Unsubscribe:
http://mail.python.org/mailman/options/python-3000/archive%40mail-archive.com