如何获取绑定方法的定义类?

2024-04-24 09:32:48 发布

您现在位置:Python中文网/ 问答频道 /正文

我成了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])

在decorator中,我需要检查包装的类__repr__是在类中被重写还是属于父类。如果__repr__已被类重写,那么我不希望auto\repr做任何事情,但是,如果不是,那么显然希望auto repr做它该做的事情。我通过比较repr方法通过__qualname__绑定的类的字符串名,成功地拼凑出一个解决方案,但感觉既便宜又笨重。理想情况下,我希望正确地检查标识if cls is repr_defined_in_cls。你知道吗

我看到的所有SO问题都只涉及获取类的字符串名称,而不是用于比较的类。有没有更好的方法来获取定义方法的(原始)类?你知道吗


Tags: inselfautoreturnifdefdecoratorprops
2条回答

当然,沿着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

完全取决于您需要的语义。我想你明白要点了。你知道吗

检查类__dict__中的"__repr__"键:

if "__repr__" in vars(cls):
    # repr overriden in class. Don't mess with it
else:
    cls.__repr__ = AutoRepr.__repr__

相关问题 更多 >