python-3.x 如何从装饰器的参数中删除self参数(如果有)

rbl8hiat  于 2023-02-01  发布在  Python
关注(0)|答案(2)|浏览(134)

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

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的解决方案,代码很长,但是在这种伟大而简单易用的编程语言中,一定有更短、更容易的方法。
EDIT:使用@staticmethod对我来说不是一个选项,因为我需要在方法本身中使用self参数。我只是不希望它被 * 打印出来 *。

w1jd8yoj

w1jd8yoj1#

最简单的方法是显式地告诉你的装饰器它正在装饰一个类方法,你的装饰器将接受一个关键字参数来表示这一点。

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")

由于用户已经知道他们在装饰什么,因此可以避免装饰器中复杂的内省代码,并为用户提供处理或不处理第一个参数的灵活性。
请看我对这条问题的回答:带参数的装饰器--一种更干净的(恕我直言)带参数的装饰器的编写方法。在那篇文章里有一些很好的答案。

tyg4sfes

tyg4sfes2#

你可以通过一些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']

相关问题