【问题标题】:How can I mark Python methods using Decorators?如何使用装饰器标记 Python 方法?
【发布时间】:2021-07-16 00:15:40
【问题描述】:

我有一个 python 类的形式

class MyClass:
    
    def __init__(self, *args, **kwargs):
        self.lst = [MyClass.method1]

    def method1(self):
        pass

    def method2(self):
        pass

我把这个类扩展成派生类:

class MyDerivedClass(MyClass):
    
    def __init__(self, *args, **kwargs):
        self.lst = [MyDerivedClass.method1, MyDerivedClass.method3]

    def method3(self):
        pass

    def method4(self):
        pass

列表lst 包含特定的方法选择:在基类中,它应该只包含method1,而在派生类中只包含method1 和method3。我想自动创建lst,而不必覆盖__init__(原因是,在我的情况下,覆盖__init__非常复杂,并且有很多方法)。有没有办法用这样的装饰器做到这一点?

@might_have_to_use_class_decorator?
class MyClass:
    
    def __init__(self, *args, **kwargs):
        lst = #automatically compile marked methods -> [method1]

    @mark_this_method
    def method1(self):
        pass

    def method2(self):
        pass

@might_have_to_use_class_decorator?
class MyDerivedClass(MyClass):
    
    def __init__(self, *args, **kwargs):
        lst = # automatically compiled, [method1, method3]

    @mark_this_method
    def method3(self):
        pass

    def method4(self):
        pass

有没有办法使用装饰器来做到这一点,也许是通过装饰我们的类?

【问题讨论】:

  • 只使用类变量?
  • 明确一点,lst只能包含类方法/静态方法,不能包含实例方法?我建议您编辑标题以阐明“类方法”。
  • @smci 可以使用实例方法没有问题,只要手动传入正确的self参数即可。

标签: python decorator


【解决方案1】:

正如@juanpa.arrivillaga 所建议的那样,简单的方法是在类变量中保留一个方法名称列表,但如果这不适合您,您确实可以使用装饰器来做到这一点。

诀窍是使用方法装饰器动态分配方法对象的属性,然后使用类装饰器枚举所有方法。

def mark_method(method):
    method.is_marked = True
    return method

def class_with_marked_methods(cls):
    parent_marked_methods = getattr(cls, "marked_methods", ())
    marked_methods = list(parent_marked_methods)
    for method in cls.__dict__.values():
        if getattr(method, "is_marked", False):
            marked_methods.append(method)
    cls.marked_methods = tuple(marked_methods)
    return cls

@class_with_marked_methods
class MyClass:
    @mark_method
    def method1(self):
        pass

    def method2(self):
        pass

@class_with_marked_methods
class MyDerivedClass(MyClass):
    @mark_method
    def method3(self):
        pass

    def method4(self):
        pass

print([method.__name__ for method in MyDerivedClass.marked_methods])
# prints ["method1", "method3"]

我已将marked_methods 属性设为元组,这样它在创建后就无法更改,但它可以很容易地成为一个列表。

【讨论】:

    猜你喜欢
    • 2015-05-25
    • 2019-02-03
    • 2010-10-16
    • 1970-01-01
    相关资源
    最近更新 更多