Here's the C source for Python's builtin ord
from the current SVN revision of bltinmodule.c:
static PyObject *
builtin_ord(PyObject *self, PyObject* obj)
{
long ord;
Py_ssize_t size;
if (PyString_Check(obj)) {
size = PyString_GET_SIZE(obj);
if (size == 1) {
ord = (long)((unsigned char)*PyString_AS_STRING(obj));
return PyInt_FromLong(ord);
}
} else if (PyByteArray_Check(obj)) {
size = PyByteArray_GET_SIZE(obj);
if (size == 1) {
ord = (long)((unsigned char)*PyByteArray_AS_STRING(obj));
return PyInt_FromLong(ord);
}
#ifdef Py_USING_UNICODE
} else if (PyUnicode_Check(obj)) {
size = PyUnicode_GET_SIZE(obj);
if (size == 1) {
ord = (long)*PyUnicode_AS_UNICODE(obj);
return PyInt_FromLong(ord);
}
#endif
} else {
PyErr_Format(PyExc_TypeError,
"ord() expected string of length 1, but " \
"%.200s found", obj->ob_type->tp_name);
return NULL;
}
PyErr_Format(PyExc_TypeError,
"ord() expected a character, "
"but string of length %zd found",
size);
return NULL;
}
As you can see, it doesn't make any method calls on the instance you pass in. As far as I can tell, if you don't pass it an explicit string, there's no way to override the functionality of ord
.
In fact, it's essentially verifying that the PyObject is either a string, byte array, or Unicode -- that's what the PyString_Check, etc. functions do. If it's none of those, you get the TypeError exception.
One workaround that doesn't scale very well would be to write your own ord
in the global namespace:
>>> class STR(str):
... def __int__(self):
... return 42
...
>>>
>>> def ord(s):
... if isinstance(s, STR):
... return int(s)
... else:
... return __builtins__.ord(s)
...
>>>
>>> ord(STR('fdsafds'))
42
>>> ord("!")
33
Of course, this scales horribly because another module using your class may be directly calling __builtins__.ord
, or they might even be overwriting ord
themselves! But, if you only need this to work on a single, standalone module, this is one way to go about it.