如何在Python中为str子代覆盖ord行为?

发布于 2024-08-14 01:26:14 字数 325 浏览 2 评论 0原文

我有这样的课程:

class STR(str):

    def __int__(self):
        return 42 

如果我像这样在提示中使用它:

>>> a=STR('8')
>>> ord(a)
56
>>> int(a)
42
>>> chr(a)
'*'

那就是行为。我想将 ord(a) 设为 42。我该怎么做?我应该在 str 类中重写哪个方法?所有这些都记录在任何地方吗?

谢谢!

I have this class:

class STR(str):

    def __int__(self):
        return 42 

If i use it in the promt like this:

>>> a=STR('8')
>>> ord(a)
56
>>> int(a)
42
>>> chr(a)
'*'

that's the behaivour. I'd like to ord(a) be 42. How can I do it? Which method should I override in the str class? Is all this documented anywhere?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

巷子口的你 2024-08-21 01:26:14

以下是来自 bltinmodule.c 的当前 SVN 版本

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;
}

如您所见,它不会对您传入的实例进行任何方法调用。据我所知,如果您不要向其传递显式字符串,因为无法覆盖 ord 的功能。

事实上,它本质上是验证 PyObject 是字符串、字节数组还是 Unicode —— 这就是 PyString_Check 等函数的作用。如果不是这些,您将收到 TypeError 异常。

一种扩展性不太好的解决方法是在全局命名空间中编写您自己的 ord

>>> 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

当然,这种扩展性非常糟糕,因为使用您的类的另一个模块可能会直接调用 __builtins__.ord,或者它们甚至可能会覆盖 ord 本身!但是,如果您只需要在单个独立模块上工作,这是一种方法。

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.

儭儭莪哋寶赑 2024-08-21 01:26:14

有人已经发布了内置的 ord 代码,并且没有您可以拦截的方法调用。

一种解决方案可以覆盖 ord 函数,例如:

backup_ord = ord
def ord(obj):
    if hasattr(obj, '__ord__'):
        return obj.__ord__()
    else:
        return backup_ord(obj)

然后使用 __ord__ 方法定义类并执行以下操作:

class MyStr(str):
    def __ord__(self):
        return 'LOL'

对于测试:

normal_five = '5'
strange_five = MyStr('5')
print ord(normal_five)
print ord(strange_five)

输出:

53
LOL

Somebody already posted the builtin ord code, and there is no method call you may intercept.

One solution could be override the ord function, for example:

backup_ord = ord
def ord(obj):
    if hasattr(obj, '__ord__'):
        return obj.__ord__()
    else:
        return backup_ord(obj)

Then you define your class with the __ord__ method and do something like:

class MyStr(str):
    def __ord__(self):
        return 'LOL'

For tests:

normal_five = '5'
strange_five = MyStr('5')
print ord(normal_five)
print ord(strange_five)

Outputs:

53
LOL
酒儿 2024-08-21 01:26:14

ord 不可重载,它不会调用字符串对象上的任何方法(至少在 CPython 中 - Python/bltinmodule.cbuiltin_ord 函数)。

最好的方法可能是创建 STR.ord 方法并调用它而不是内置方法。

ord is not overloadable, it doesn't call any method on string objects (at least in CPython - Python/bltinmodule.c, builtin_ord function).

The best way is probably to create STR.ord method and call that instead of the built-in.

凡尘雨 2024-08-21 01:26:14

您不能覆盖 ord,但您可以覆盖为变量,例如

备份原始 ord

origord= ord

def ord(x):
    return 42


ord(a)
42

origord(a)
56

但我认为覆盖它不是一个好主意。

You can't override ord but you can overwrite as variable for example

backup original ord

origord= ord

def ord(x):
    return 42


ord(a)
42

origord(a)
56

But I think its not good a idea to overwrite it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文