Python 不使用类的装饰器的参数

Python 不使用类的装饰器的参数,python,class,python-decorators,Python,Class,Python Decorators,我有点困惑为什么这不起作用,特别是这一部分:@tracer(enabled=False) 我所理解的是: 每当tracer执行调用时,函数对象rotate\u list将作为参数传递 我认为这不起作用的原因是tracer(以及任何包装器)只接受可调用对象,enabled=False不是可调用对象,所以它不起作用 然而,错误消息并不能很好地说明这一点,因此我想知道为什么错误消息是: TypeError:tracer()缺少1个必需的位置参数:“func” 我猜括号内的参数是首先计算的,这样就没有可

我有点困惑为什么这不起作用,特别是这一部分:
@tracer(enabled=False)

我所理解的是: 每当
tracer
执行调用时,函数对象
rotate\u list
将作为参数传递

我认为这不起作用的原因是tracer(以及任何包装器)只接受可调用对象,
enabled=False
不是可调用对象,所以它不起作用

然而,错误消息并不能很好地说明这一点,因此我想知道为什么错误消息是:
TypeError:tracer()缺少1个必需的位置参数:“func”

我猜括号内的参数是首先计算的,这样就没有可调用对象被传递给tracer了

我想这可以通过使用类装饰器来解决,比如

def tracer(func, enabled=True):
    def wrap(*args, **kwargs):
        if enabled:
            print('Calling {}'.format(func))
        return func(*args, **kwargs)
    return wrap


@tracer(enabled=False)
def rotate_list(l):
    return l[1:] + [l[0]]
然后
tracer=Trace(enabled=True)
就可以工作了,但是我想看看如何在不使用类的情况下解决这个问题

============

编辑(解决方案): 别介意,只是把它打出来,以确保我理解了解决方案。 因为将参数放在装饰器中会使它像普通函数一样工作。解决方案是使该装饰器返回另一个可调用对象(即实际的装饰器)

比如:
@dec
def foo:pass
将变成
foo=dec(foo)

@dec(ARG)
def foo:pass
将变成
foo=dec(ARG)(foo)

解决方案是让
dec
返回另一个可调用的,即实际的装饰器。例如,该函数将是
wrap

foo=dec(ARG)(foo)
将变成
foo=wrap(foo)
,其中
ARG
已传递给
dec

谢谢大家!我喜欢函数编程。

要将函数以外的其他参数传递给嵌套多个def的decorator函数,请执行以下操作:

class Trace:
    def __init__(self, enabled=False):
        print('Inside __init__')
        self.enabled = enabled
编辑 此装饰器帮助构建其他装饰器。虽然它包含多个嵌套函数,但它允许您仅使用两个层和参数定义装饰器,就像您所做的那样:

def my_decorator(flagDoThat)
    def internal(func):
        def wrapper(*argv, **kwv):
            retval = func(*argv, **kwv)
            if flagDoThat:
                print("Hello", retval)
            return retval

        wrapper.__name__ = func.__name__ #update name
        return wrapper
    return internal

@my_decorator(True)
def my_func(): return "world"

#equals to

tmp = my_decorator(True)

@tmp
def my_func(): return "world"
可以这样使用:

def decorator(keepFunctionName=True):
    def internal(func):
        def newFunc(*argv, **kwv):
            def decoWrapper(theFuncUsedInFunc):
                fRet = func(theFuncUsedInFunc, *argv, **kwv)
                if keepFunctionName:
                    fRet.__name__ = theFuncUsedInFunc.__name__
                return fRet
            return decoWrapper
        return newFunc
    return internal
class my_decorator:
    __slots__ = ["flagDoThat"] # optional line
    def __init__(self, flagDoThat):
        self.flagDoThat = flagDoThat

    def __call__(self, func):
        def wrapper(*argv, **kwv):
            retval = func(*argv, **kwv)
            if self.flagDoThat:
                print("Hello", retval)
            return retval

        return wrapper
def foo(): pass
foo = dec(foo)
而这个装饰者正是上面的装饰者所做的

编辑二 通过将decorator附加到init函数,可以对类执行相同的操作

但这里有另一种方法,可以通过将参数存储在类中来生成具有参数的装饰器:

@decorator()
def my_decorator(func, flagDoThat):
    def wrapper(*argv, **kwv):
        retval = func(*argv, **kwv)
        if flagDoThat:
            print("Hello", retval)
        return retval

    return wrapper

要将函数以外的其他参数传递给装饰函数,请嵌套多个def:

class Trace:
    def __init__(self, enabled=False):
        print('Inside __init__')
        self.enabled = enabled
编辑 此装饰器帮助构建其他装饰器。虽然它包含多个嵌套函数,但它允许您仅使用两个层和参数定义装饰器,就像您所做的那样:

def my_decorator(flagDoThat)
    def internal(func):
        def wrapper(*argv, **kwv):
            retval = func(*argv, **kwv)
            if flagDoThat:
                print("Hello", retval)
            return retval

        wrapper.__name__ = func.__name__ #update name
        return wrapper
    return internal

@my_decorator(True)
def my_func(): return "world"

#equals to

tmp = my_decorator(True)

@tmp
def my_func(): return "world"
可以这样使用:

def decorator(keepFunctionName=True):
    def internal(func):
        def newFunc(*argv, **kwv):
            def decoWrapper(theFuncUsedInFunc):
                fRet = func(theFuncUsedInFunc, *argv, **kwv)
                if keepFunctionName:
                    fRet.__name__ = theFuncUsedInFunc.__name__
                return fRet
            return decoWrapper
        return newFunc
    return internal
class my_decorator:
    __slots__ = ["flagDoThat"] # optional line
    def __init__(self, flagDoThat):
        self.flagDoThat = flagDoThat

    def __call__(self, func):
        def wrapper(*argv, **kwv):
            retval = func(*argv, **kwv)
            if self.flagDoThat:
                print("Hello", retval)
            return retval

        return wrapper
def foo(): pass
foo = dec(foo)
而这个装饰者正是上面的装饰者所做的

编辑二 通过将decorator附加到init函数,可以对类执行相同的操作

但这里有另一种方法,可以通过将参数存储在类中来生成具有参数的装饰器:

@decorator()
def my_decorator(func, flagDoThat):
    def wrapper(*argv, **kwv):
        retval = func(*argv, **kwv)
        if flagDoThat:
            print("Hello", retval)
        return retval

    return wrapper

它只能通过函数来完成<代码>跟踪器应如下所示:

def decorator(keepFunctionName=True):
    def internal(func):
        def newFunc(*argv, **kwv):
            def decoWrapper(theFuncUsedInFunc):
                fRet = func(theFuncUsedInFunc, *argv, **kwv)
                if keepFunctionName:
                    fRet.__name__ = theFuncUsedInFunc.__name__
                return fRet
            return decoWrapper
        return newFunc
    return internal
class my_decorator:
    __slots__ = ["flagDoThat"] # optional line
    def __init__(self, flagDoThat):
        self.flagDoThat = flagDoThat

    def __call__(self, func):
        def wrapper(*argv, **kwv):
            retval = func(*argv, **kwv)
            if self.flagDoThat:
                print("Hello", retval)
            return retval

        return wrapper
def foo(): pass
foo = dec(foo)
这里要做的是创建返回decorator的函数(tracer)。那个装饰器接受一个函数

如果您将其转换为python对任何装饰器所使用的相同格式,您将看到为什么需要这样做

每次python看到

def tracer(enabled=False):
    def wrapper(func):
        def wrap(*args, **kwargs):
            if enabled:
                print('Calling {}'.format(func))
            return func(*args, **kwargs)
        return wrap
    return wrapper
它可以翻译为:

@dec
def foo(): pass
因此,当您有需要参数的decorator时,它的翻译如下:

def decorator(keepFunctionName=True):
    def internal(func):
        def newFunc(*argv, **kwv):
            def decoWrapper(theFuncUsedInFunc):
                fRet = func(theFuncUsedInFunc, *argv, **kwv)
                if keepFunctionName:
                    fRet.__name__ = theFuncUsedInFunc.__name__
                return fRet
            return decoWrapper
        return newFunc
    return internal
class my_decorator:
    __slots__ = ["flagDoThat"] # optional line
    def __init__(self, flagDoThat):
        self.flagDoThat = flagDoThat

    def __call__(self, func):
        def wrapper(*argv, **kwv):
            retval = func(*argv, **kwv)
            if self.flagDoThat:
                print("Hello", retval)
            return retval

        return wrapper
def foo(): pass
foo = dec(foo)
所以,您需要做的是确保decorator返回接受函数作为其参数的内容


PS:使用decorator保留函数名、docstring等很好。

这只能通过函数来完成<代码>跟踪器应如下所示:

def decorator(keepFunctionName=True):
    def internal(func):
        def newFunc(*argv, **kwv):
            def decoWrapper(theFuncUsedInFunc):
                fRet = func(theFuncUsedInFunc, *argv, **kwv)
                if keepFunctionName:
                    fRet.__name__ = theFuncUsedInFunc.__name__
                return fRet
            return decoWrapper
        return newFunc
    return internal
class my_decorator:
    __slots__ = ["flagDoThat"] # optional line
    def __init__(self, flagDoThat):
        self.flagDoThat = flagDoThat

    def __call__(self, func):
        def wrapper(*argv, **kwv):
            retval = func(*argv, **kwv)
            if self.flagDoThat:
                print("Hello", retval)
            return retval

        return wrapper
def foo(): pass
foo = dec(foo)
这里要做的是创建返回decorator的函数(tracer)。那个装饰器接受一个函数

如果您将其转换为python对任何装饰器所使用的相同格式,您将看到为什么需要这样做

每次python看到

def tracer(enabled=False):
    def wrapper(func):
        def wrap(*args, **kwargs):
            if enabled:
                print('Calling {}'.format(func))
            return func(*args, **kwargs)
        return wrap
    return wrapper
它可以翻译为:

@dec
def foo(): pass
因此,当您有需要参数的decorator时,它的翻译如下:

def decorator(keepFunctionName=True):
    def internal(func):
        def newFunc(*argv, **kwv):
            def decoWrapper(theFuncUsedInFunc):
                fRet = func(theFuncUsedInFunc, *argv, **kwv)
                if keepFunctionName:
                    fRet.__name__ = theFuncUsedInFunc.__name__
                return fRet
            return decoWrapper
        return newFunc
    return internal
class my_decorator:
    __slots__ = ["flagDoThat"] # optional line
    def __init__(self, flagDoThat):
        self.flagDoThat = flagDoThat

    def __call__(self, func):
        def wrapper(*argv, **kwv):
            retval = func(*argv, **kwv)
            if self.flagDoThat:
                print("Hello", retval)
            return retval

        return wrapper
def foo(): pass
foo = dec(foo)
所以,您需要做的是确保decorator返回接受函数作为其参数的内容


PS:很高兴使用decorator保留函数名、docstring等。

谢谢,我现在就知道了。谢谢,我现在就知道了。