如果有一个,如何从装饰器的参数中删除 self 参数

How to remove the self argument from a decorator's arguments if there is one

假设我有一个简单的装饰器,一个 类 方法和一个函数,我都用那个装饰器装饰:

import functools

def decorator(func):
    @functools.wraps(func)
    def call(*args):
        print(args)
        func(*args)
    return call

class cls:
    @decorator
    def meth(self, a):
        pass

@decorator
def func(c):
    pass

cls().meth("a")
func("c")

我得到以下输出:

(<__main__.cls object at 0x7f4665c50130>, 'a')
('c',)

但是我想在方法上使用装饰器时删除 self 参数,以便输出变为:

('a',)
('c',)

但是,如果我简单地添加 args.pop(0),我将删除第一个参数,即使它不是 self。如果第一个参数是 self,我如何才能删除它?

注意:我使用 inspect 阅读了一些带有长代码的解决方案 - 但在这个伟大且易于使用的方法中必须有更短、更简单的方法编程语言 ?

编辑:使用@staticmethod对我来说不是一个选项,因为我需要方法本身的self参数。我只是不想印刷.

实现此目的的最简单方法是明确告诉您的装饰器它正在装饰一个 class 方法。您的装饰器将采用一个关键字参数来表示。

def decorator(is_classmethod=False):
    def wrapper(func):
        @functools.wraps(func)
        def call(*args):
            if is_classmethod:
                print(args[1:])  # omit args[0]
            else:
                print(args)
            return func(*args)      # pass all the args to the function
        return call
    return wrapper

class cls:
    @decorator(is_classmethod=True)
    def meth(self, a):
        pass

@decorator
def func(c):
    pass

cls().meth("a")
func("c")

既然用户已经知道他们在装饰什么,你可以避免装饰器中复杂的内省代码,并让用户灵活地处理或不处理第一个参数。

请查看我对这个 SO 问题的回答:Decorators with parameters? 以更简洁(恕我直言)的方式编写带参数的装饰器。 post.

中有一些非常好的答案

您可以通过某些 python 魔法过滤 args 输出。例如:

import functools

def decorator(func):
    @functools.wraps(func)
    def call(*args):
        print(list(filter(lambda x: not hasattr(x, '__dict__'), args)))
        func(*args)
    return call

class cls:
    @decorator
    def meth(self, a):
        pass

@decorator
def func(c):
    pass

cls().meth("a")  # ['a']
func("c")  # ['c']