Python Expert:如何继承内置类并覆盖每个成员函数 w.r.t.基类成员函数?

Posted

技术标签:

【中文标题】Python Expert:如何继承内置类并覆盖每个成员函数 w.r.t.基类成员函数?【英文标题】:Python Expert: how to inherit built-in class and override every member function w.r.t. the base-class member function? 【发布时间】:2022-01-23 09:33:24 【问题描述】:

众所周知,在Python中,出于优化的考虑,我们不能添加/修改内置类的成员函数,例如,在内置str类中添加sed函数来执行@987654323 @。因此,实现这一点的唯一方法是继承类(或子类)。即,

class String(str):
    def __init__(self, value='', **kwargs):
        super().__init__()

    def sed(self, src, tgt):
        return String(re.sub(src, tgt, self))

这样做的问题是,子类化后,成员函数返回基类实例而不是继承的类实例。例如,我想链接字符串编辑String(' A b C d E [!] ').sed(...).lower().sed(...).strip().sed('\[.*\]', '').split() 等等。但是,.lower().strip() 等函数返回str 而不是String,因此之后无法执行.sed(...)。而且我不想在每次函数调用后继续转换为String

所以我手动覆盖了每个基类方法,如下所示:

class String(str):
    for func in dir(str):
        if not func.startswith('_'):
            exec(f'func=lambda *args, **kwargs: [(String(i) if type(i)==str else i) for i in [str.func(*args, **kwargs)]][0]')

    def __init__(self, value='', **kwargs):
        super().__init__()

    def sed(self, src, tgt):
        return String(re.sub(src, tgt, self))

然而,并不是每个成员函数都返回一个简单的str 对象,例如,对于.split() 等函数,它们返回一个str 的列表; .isalpha().find() 等其他函数返回布尔值或整数。一般来说,我想添加更多的字符串变形函数,并且不想手动覆盖每个返回类型的成员函数,以便返回继承类对象而不是基类对象。那么有没有更优雅的方式来做到这一点?谢谢!

【问题讨论】:

优雅的方式是不去做。在您的示例中,我看到您的 sed() 函数对字符串类没有附加值,但我看到了一个非常具体的用例,它最终作为字符串替换。如果您的字符串自定义没有超过该复杂性,那么使用re.sub() 等众所周知的操作而不是您自己的包装对您的其他编码人员来说更加优雅和富有表现力。如果您的自定义确实合理,那么答案是您自己的字符串类,您可以在其中覆盖您认为合适的任何操作。如果你暴露了这样的低级操作,你的类 API 可能还没有完成。 @FlorinC。这里我说的是精英编码,所以不要对我的例子中的re.sub() 感到困惑(这与.sed() 几乎没有区别)。目标是修补基函数中的每个函数,将输出变为继承实例而不是基实例。 【参考方案1】:

Python 的内置类并非旨在支持这种继承风格 容易地。此外,在我看来,整个想法似乎有缺陷。即使你弄清楚了 一种解决问题的方法,因为你已经框架了它,有什么好处比好 旧功能?

# Special String objects with new methods.

s = String('foo bar')
result = s.sed('...', '...')

# Regular str instances passed to ordinary functions.

s = 'foo bar'
result = sed(s, '...', '...')

也就是说,这是一种尝试方法。我没有测试过 广泛地说,它可能有一个缺陷,我永远不会在实际代码中使用它。 基本思想是捕获低级期间返回的对象 属性访问,如果对象是可调用的,则返回 它的包装版本将执行所需的 数据转换。

import re
from functools import wraps

class String(str):

    def __getattribute__(self, attr):
        obj = object.__getattribute__(self, attr)
        return wrapped(obj) if callable(obj) else obj

    def __init__(self, value='', **kwargs):
        super().__init__()

    def sed(self, src, tgt):
        return re.sub(src, tgt, self)

def wrapped(func):

    @wraps(func)
    def wrapper(*xs, **kws):
        obj = func(*xs, **kws)
        return convert(obj)

    return wrapper

def convert(obj):
    if isinstance(obj, str):
        return String(obj)
    elif isinstance(obj, list):
        return [convert(x) for x in obj]
    elif isinstance(obj, tuple):
        return tuple(convert(x) for x in obj)
    else:
        return obj

演示:

s = String('foo bar')
got = s.sed('foo', 'bzz').upper().split()
print(got)
print(type(got))
print(type(got[0]))

输出:

['BZZ', 'BAR']
<class 'list'>
<class '__main__.String'>

【讨论】:

我的整个想法是能够链接字符串编辑函数以进行短编码。我看不出里面有什么缺陷。顺便说一句,修改原始类中的每个函数是一种非常常见的技术,而不仅仅是内置类。 @xuancong84 意见不一。但是,如上所示,代码并非如此短。并且修改另一个类中的每个函数肯定不是一种常见的技术:我知道;我已经看到它完成了;但远不常见。

以上是关于Python Expert:如何继承内置类并覆盖每个成员函数 w.r.t.基类成员函数?的主要内容,如果未能解决你的问题,请参考以下文章

SQLite Expert Professional 如何设置主键和外键

python继承细节

cocos2d 如何创建继承与 ccsprite的类并在项目中使用

从继承的类中覆盖虚拟方法但保留基类的注释[重复]

Python继承

覆盖基类成员变量的初始值