python - 如何获取绑定(bind)方法的定义类?

标签 python python-3.x

我做了一个 AutoRepr 类和类 decorator...

class AutoRepr:
    def __repr__(self):
        def _fix(thing):
            if isinstance(thing, str):
                return f'"{thing}"'
            if isinstance(thing, Iterable):
                s = str(thing)
                if len(s) > 30:
                    return type(thing)
                else:
                    return s
            return thing

        props = []
        try:
            for attr in self.__slots__:
                if attr.startswith('_'):
                    continue
                try:
                    attr_val = getattr(self, attr)
                    if attr_val:
                        props.append(f'{attr}={_fix(attr_val)}')
                except AttributeError:
                    pass
        except AttributeError:
            props = [f'{k}={_fix(v)}'
                     for k, v in self.__dict__.items()
                     if not k.startswith('_')]
        return f'{type(self).__name__}({", ".join(props)})'


def auto_repr(override_all=False):
    def decorator(cls):
        repr_defined_in = cls.__repr__.__qualname__.split('.')[0]
        if not override_all and repr_defined_in == cls.__name__:
            # repr overriden in class. Don't mess with it
            return cls
        cls.__repr__ = AutoRepr.__repr__
        return cls

    return decorator

# Example 1
@auto_repr()
class MyClass:
    def __init__(self):
        self.strength = None
        self.weakness = 'cake'

# Example 2
class Another(AutoRepr):
    __slots__ = ('num', 'my_list')
    def __init__(self):
        self.num = 12
        self.my_list = [1, 2, 3]


f = MyClass()
print(f)

b = Another()
print(b)

# MyClass(strength=None, weakness="cake")
# Another(num=12, my_list=[1, 2, 3])

在装饰器中,我需要检查包装类 __repr__ 是否在类中被覆盖或是否属于父类。如果 __repr__ 已被类覆盖,那么我不希望 auto_repr 做任何事情,但是,如果没有,那么显然希望 auto-repr 做它的事情。通过 __qualname__ 比较 repr 方法绑定(bind)类的字符串名称,我设法拼凑出一个解决方案,但感觉既便宜又笨重。理想情况下,我想正确检查身份if cls is repr_defined_in_cls

我见过的所有 SO 问题都只解决获取类的字符串名称,而不是用于比较的类。有没有更好的方法来获取定义方法的(原始)类?

最佳答案

当然,走 mro 并确保您点击的第一个 __repr__ 不是来自 object:

In [18]: class A:
    ...:     pass
    ...:
    ...: class B(A):
    ...:     def __repr__(self): return "a repr"
    ...:
    ...: class C(B):
    ...:     pass
    ...:
    ...:

In [19]: def is_non_default_repr(klass):
    ...:     for superclass in klass.mro():
    ...:         if '__repr__' in vars(superclass):
    ...:             return superclass is not object
    ...:     return False # should we ever get here? maybe raise error?
    ...:
    ...:

In [20]: is_non_default_repr(A)
Out[20]: False

In [21]: is_non_default_repr(B)
Out[21]: True

In [22]: is_non_default_repr(C)
Out[22]: True

我相信,如果元类使用 __slots__,这将失败,但那将是一个非常反常的现象。

编辑:

重新阅读您的要求,您可以执行以下操作:

In [23]: def which_method(klass, methodname):
    ...:     for superclass in klass.mro():
    ...:         if methodname in vars(superclass):
    ...:             return superclass
    ...:     raise ValueError(f"{methodname} not a member")
    ...:
    ...:

In [24]: which_method(C, '__repr__') is not object
Out[24]: True

In [25]: which_method(C, '__repr__')
Out[25]: __main__.B

In [26]: which_method(C, '__repr__') is C
Out[26]: False

In [27]: which_method(B, '__repr__') is B
Out[27]: True

具体取决于您需要的语义。我想您明白了要点。

关于python - 如何获取绑定(bind)方法的定义类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53889849/

相关文章:

python - 如何将 Microsoft Azure 中的 pip 从 1.5.6 升级到 9.0.1?

python - 如何汇总每行时间前 1 小时到后 1 小时的价格,Pandas

python-3.x - 矩阵未对齐错误: Python SciPy fmin_bfgs

python - 如何将未知时区的字符串datetime转换为python中的时间戳

python - 读取 txt 文件并将各个列保存为列表

Python:如何找到连续系列中第一个和最后一个字符的索引

python - 在每个元素上使用条件的 Numpy 过滤器

python - 从字典创建 pandas 数据框

查找连续重复的单词时 Python 后视正则表达式 "fixed-width pattern"错误

python - 如何对二叉搜索树中给定值下的所有节点求和?